Skip to content
This repository was archived by the owner on Nov 21, 2024. It is now read-only.

Commit 744f57e

Browse files
committed
Updates from private repo
1 parent 9759527 commit 744f57e

File tree

1 file changed

+301
-71
lines changed

1 file changed

+301
-71
lines changed

bookmark/bookmark.js

Lines changed: 301 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,93 +1,323 @@
11
/** File: bookmark.js
2-
* Candy Plugin - Bookmark rooms
2+
* Candy Plugin - Bookmark Rooms
3+
* Author: Rafael Macedo <[email protected]>
34
* Author: Ben Langfeld <[email protected]>
45
*/
56

6-
/* global Candy, jQuery, Strophe, $iq */
7-
87
var CandyShop = (function(self) { return self; }(CandyShop || {}));
98

109
CandyShop.Bookmark = (function(self, Candy, $) {
11-
self.init = function(){
12-
$(Candy).on('candy:view.connection.status-5', function(){
13-
self._createBookmarksNode();
14-
return true;
15-
});
10+
11+
self.Bookmark = (function() {
12+
function Bookmark(type, args) {
13+
this.type = type;
14+
this.jid = args.jid;
15+
this.name = args.name || args.jid.split(/@/)[0];
16+
this.id = args.room_id || args.user_id;
17+
this.term = args.term;
18+
this.to = args.to;
19+
this.opened = false;
20+
this.is_private = args.is_private;
21+
this.pending_removal = false;
22+
}
23+
24+
Bookmark.prototype.join = function(foreground) {
25+
if (!this.opened) {
26+
if (this.type.match(/users/)) {
27+
Candy.View.Pane.PrivateRoom.open(this.jid, this.name, foreground, true);
28+
} else if (this.type.match(/rooms/)) {
29+
var data = { roomJid: this.jid, name: this.name, is_private: this.is_private, room_id: this.id };
30+
CandyShop.JoinOnResponse.joinRoom(data, false, foreground);
31+
} else {
32+
Candy.Core.warn('Error: unknown bookmark type: ', this.type);
33+
}
34+
this.opened = true;
35+
}
36+
};
37+
38+
Bookmark.prototype.leave = function() {
39+
if (this.type.match(/users/)) {
40+
Candy.View.Pane.Room.close(this.jid);
41+
} else if (this.type.match(/rooms/)) {
42+
Candy.Core.Action.Jabber.Room.Leave(this.jid);
43+
}
44+
};
45+
46+
Bookmark.prototype.toArgs = function() {
47+
var args = {};
48+
49+
if (this.id) {
50+
if (this.type.match(/users/)) {
51+
args.user_id = this.id;
52+
} else if (this.type.match(/rooms/)) {
53+
args.room_id = this.id;
54+
}
55+
} else {
56+
if (this.type.match(/users/)) {
57+
args.user_jid = this.jid;
58+
} else if (this.type.match(/rooms/)) {
59+
args.room_jid = this.jid;
60+
}
61+
}
62+
63+
return args;
64+
};
65+
66+
return Bookmark;
67+
})();
68+
69+
self.BookmarkCollection = (function() {
70+
function BookmarkCollection() {
71+
this.collection = [];
72+
this.version = undefined;
73+
}
74+
75+
BookmarkCollection.prototype.add = function(bookmark, newlyAdded) {
76+
if (this.collection.filter(function(item) { return item.jid === bookmark; }).length === 0) {
77+
if (newlyAdded) {
78+
this.collection.unshift(bookmark);
79+
if (Candy.Core.getConnection().connected === true) {
80+
bookmark.join();
81+
}
82+
} else {
83+
this.collection.push(bookmark);
84+
}
85+
}
86+
return this.collection;
87+
};
88+
89+
BookmarkCollection.prototype.joinAll = function() {
90+
this.collection.forEach(function (bookmark, position, collection) {
91+
var foreground = false;
92+
if (CandyShop.RoomAnchors.roomAnchorJid()) {
93+
// This bookmark matches the room in the URL
94+
if (CandyShop.RoomAnchors.roomAnchorJid() === bookmark.jid) {
95+
foreground = true;
96+
}
97+
} else if (position === 0) {
98+
foreground = true;
99+
}
100+
bookmark.join(foreground);
101+
});
102+
}
103+
104+
BookmarkCollection.prototype.jids = function() {
105+
return this.collection.map(function(bookmark) {
106+
return bookmark.jid;
107+
});
108+
};
109+
110+
BookmarkCollection.prototype.pendingRemoval = function() {
111+
return this.collection.filter(function(item) { return item.pending_removal; });
112+
};
113+
114+
BookmarkCollection.prototype.valid = function() {
115+
return this.collection.filter(function(item) { return !item.pending_removal; });
116+
};
117+
118+
BookmarkCollection.prototype.tryRemoveByJid = function(jid) {
119+
this.collection.forEach(function (item) {
120+
if (item.jid === jid) {
121+
item.pending_removal = true;
122+
}
123+
});
124+
};
125+
126+
BookmarkCollection.prototype.removeByJid = function(jid) {
127+
this.collection = this.collection.filter(function(bookmark) {
128+
return bookmark.jid !== jid;
129+
});
130+
};
131+
132+
BookmarkCollection.prototype.reset = function(data) {
133+
for (var key in data) {
134+
data[key].forEach($.proxy(function(obj) {
135+
self.bookmarks.add(new self.Bookmark(key, obj));
136+
}), this);
137+
}
138+
};
139+
140+
BookmarkCollection.prototype.sync = function(data) {
141+
for (var key in data) {
142+
data[key].forEach($.proxy(function(obj) {
143+
if ($.inArray(obj.jid, self.bookmarks.jids()) === -1) {
144+
self.bookmarks.add(new self.Bookmark(key, obj));
145+
}
146+
}), this);
147+
}
148+
149+
var jids = [];
150+
jids = jids.concat(data.connect_bookmarked_users.map(function(i) { return i.jid; }));
151+
jids = jids.concat(data.connect_bookmarked_rooms.map(function(i) { return i.jid; }));
152+
153+
this.valid().forEach($.proxy(function(item) {
154+
if ($.inArray(item.jid, jids) === -1) {
155+
this.removeByJid(item.jid);
156+
item.leave();
157+
}
158+
}), this);
159+
};
160+
161+
BookmarkCollection.prototype.setVersion = function(version) {
162+
this.version = version;
163+
};
164+
165+
BookmarkCollection.prototype.toArgs = function() {
166+
var args = {};
167+
var valid = this.valid();
168+
169+
args.version = this.version;
170+
171+
args.connect_bookmarked_users =
172+
valid.filter(function(bookmark) {
173+
return bookmark.type === 'connect_bookmarked_users';
174+
}).map(function(bookmark) { return bookmark.toArgs(); });
175+
176+
args.connect_bookmarked_rooms =
177+
valid.filter(function(bookmark) {
178+
return bookmark.type === 'connect_bookmarked_rooms';
179+
}).map(function(bookmark) { return bookmark.toArgs(); });
180+
181+
return args;
182+
};
183+
184+
BookmarkCollection.prototype.type = function(type) {
185+
return this.collection.filter(function(bookmark) {
186+
return bookmark.type === 'connect_bookmarked_' + type;
187+
});
188+
};
189+
190+
return BookmarkCollection;
191+
})();
192+
193+
self.requestHandler = undefined;
194+
195+
self.init = function() {
196+
self.bookmarks = new self.BookmarkCollection();
197+
self._addEventListeners();
16198
};
17-
/** File: bookmark.js
18-
* Candy Plugin - Bookmark rooms
19-
* Author: Ben Langfeld <[email protected]>
20-
*/
21199

22-
var CandyShop = (function(self) { return self; }(CandyShop || {}));
200+
self._addEventListeners = function() {
201+
$(Candy)
202+
.on('candy:core.presence.error', self._removeBookmarkPresenceError)
203+
.on('candy:view.room.after-close', self._removeBookmark)
204+
.on('candy:view.room.after-add', self._onRoomOpen)
205+
.on('candy:view.connection.status-' + Strophe.Status.CONNECTED, self.joinAll)
206+
.on('candy:view.connection.status-' + Strophe.Status.ATTACHED, self.joinAll);
207+
};
23208

24-
CandyShop.Bookmark = (function(self, Candy, $) {
25-
/** Object: about
26-
*
27-
* Contains:
28-
* (String) name - Candy Plugin - Bookmark rooms
29-
* (Float) version - Candy Plugin - Bookmark rooms
30-
*/
31-
self.about = {
32-
name: 'Candy Plugin - Bookmark rooms',
33-
version: '0.1'
209+
self.joinAll = function () {
210+
self.bookmarks.joinAll();
34211
};
35212

36-
self.init = function(){
37-
Strophe.addNamespace('PUBSUB', 'http://jabber.org/protocol/pubsub');
38-
$(Candy).on('candy:view.connection.status-5', self._createBookmarksNode);
39-
$(Candy).on('candy:view.connection.status-8', self._createBookmarksNode);
213+
self.fetchBookmarks = function(data) {
214+
self.bookmarks.setVersion(data.version);
215+
delete data.version;
216+
self.bookmarks.reset(data);
40217
};
41218

42-
/** Function: add
43-
* Adds a bookmark for the provided MUC room
44-
*
45-
* Parameters:
46-
* (String) roomJid - The JID of the room to bookmark
47-
*/
48-
self.add = function(roomJid) {
49-
Candy.Core.getConnection().sendIQ($iq({
50-
type: 'set'
51-
})
52-
.c('pubsub', {xmlns: Strophe.NS.PUBSUB})
53-
.c('publish', {node: Strophe.NS.BOOKMARKS})
54-
.c('item', {id: roomJid})
55-
.c('storage', {xmlns: Strophe.NS.BOOKMARKS})
56-
.c('conference', {autojoin: 'true', jid: roomJid})
57-
);
219+
self._onRoomOpen = function(e, args) {
220+
if (self.bookmarks) {
221+
if ($.inArray(args.roomJid, self.bookmarks.jids()) === -1) {
222+
var bookmark;
223+
var type;
224+
225+
if (args.type === 'chat') {
226+
type = 'connect_bookmarked_users';
227+
} else if (args.type === 'groupchat') {
228+
type = 'connect_bookmarked_rooms';
229+
}
230+
231+
if (type) {
232+
bookmark = new self.Bookmark(type, { jid: args.roomJid });
233+
self.bookmarks.add(bookmark, true);
234+
self._updateBookmarks();
235+
}
236+
}
237+
238+
// Re-sort the order of Rooms, and One-on-One chats to match
239+
// the order of the bookmarks
240+
var chatTabs = $('#chat-tabs');
241+
var roomsHead = $('#rooms-head').detach();
242+
var rooms = chatTabs.find('.roomtype-groupchat').detach();
243+
var peopleHead = $('#people-head').detach();
244+
var people = chatTabs.find('.roomtype-chat').detach();
245+
246+
// TODO: DRY
247+
chatTabs.append(roomsHead);
248+
self.bookmarks.type('rooms').map(function(bookmark) {
249+
chatTabs.append(rooms.filter(function(i, room) {
250+
return $(room).attr('data-roomjid') === bookmark.jid;
251+
}));
252+
});
253+
254+
chatTabs.append(peopleHead);
255+
self.bookmarks.type('users').map(function(bookmark) {
256+
chatTabs.append(people.filter(function(i, user) {
257+
return $(user).attr('data-roomjid') === bookmark.jid;
258+
}));
259+
});
260+
}
58261
};
59262

60-
/** Function: remove
61-
* Removes a bookmark for the provided MUC room
62-
*
63-
* Parameters:
64-
* (String) roomJid - The JID of the room to remove from bookmarks
65-
*/
66-
self.remove = function(roomJid) {
67-
Candy.Core.getConnection().sendIQ($iq({
68-
type: 'set'
69-
})
70-
.c('pubsub', {xmlns: Strophe.NS.PUBSUB})
71-
.c('retract', {node: Strophe.NS.BOOKMARKS})
72-
.c('item', {id: roomJid})
73-
);
263+
self._removeBookmarkPresenceError = function(e, args) {
264+
if ($(args).attr('error') && Strophe.getBareJidFromJid($(args).attr('from')) !== Strophe.getBareJidFromJid(Candy.Core.getUser().getJid())) {
265+
self._removeBookmark(e, args);
266+
}
74267
};
75268

76-
self._createBookmarksNode = function() {
77-
// We do this instead of using publish-options because this is not mandatory to implement according to XEP-0060
78-
Candy.Core.getConnection().sendIQ($iq({type: 'set'})
79-
.c('pubsub', {xmlns: Strophe.NS.PUBSUB})
80-
.c('create', {node: 'storage:bookmarks'}).up()
81-
.c('configure')
82-
.c('x', {xmlns: 'jabber:x:data', type: 'submit'})
83-
.c('field', {'var': 'FORM_TYPE', type: 'hidden'})
84-
.c('value').t('http://jabber.org/protocol/pubsub#node_config').up().up()
85-
.c('field', {'var': 'pubsub#persist_items'}).c('value').t('1').up().up()
86-
.c('field', {'var': 'pubsub#access_model'}).c('value').t('whitelist')
87-
);
88-
89-
return true;
269+
self._removeBookmark = function(e, args) {
270+
if (args.roomJid) {
271+
self.bookmarks.tryRemoveByJid(args.roomJid);
272+
window.clearTimeout(self.requestHandler);
273+
self.requestHandler = window.setTimeout(self._updateBookmarks, 300);
274+
}
90275
};
91276

277+
self._updateBookmarks = function() {
278+
$.ajax({
279+
type: 'PUT',
280+
url: '/api/v1/connect/bookmarks',
281+
contentType: 'application/json',
282+
data: JSON.stringify(self.bookmarks.toArgs()),
283+
statusCode: {
284+
409: function() {
285+
CandyShop.ConnectStateData.fetch().done(function(data) {
286+
self.bookmarks.setVersion(data.bookmarks.version);
287+
delete data.bookmarks.version;
288+
self.bookmarks.sync(data.bookmarks);
289+
self._updateBookmarks();
290+
});
291+
}
292+
}
293+
}).done(function(data) {
294+
self.bookmarks.setVersion(data.version);
295+
delete data.version;
296+
self.bookmarks.sync(data);
297+
298+
self.bookmarks.pendingRemoval().forEach(function (bookmark) {
299+
if (self._serverHasBookmark(bookmark.jid, data)) {
300+
// The server still has this bookmark. We need to sync again
301+
self._removeBookmark(undefined, { roomJid: bookmark.jid });
302+
} else {
303+
// This bookmark was removed from the server. Remove it from our local collection
304+
self.bookmarks.removeByJid(bookmark.jid);
305+
}
306+
});
307+
});
308+
};
309+
310+
self._serverHasBookmark = function (jid, data) {
311+
var has = false;
312+
for (var key in data) {
313+
data[key].forEach(function (bookmark) {
314+
if (bookmark.jid == jid) {
315+
has = true;
316+
}
317+
})
318+
}
319+
return has;
320+
}
321+
92322
return self;
93323
}(CandyShop.Bookmark || {}, Candy, jQuery));

0 commit comments

Comments
 (0)