social_stream-presence 0.0.21 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (27) hide show
  1. data/app/assets/javascripts/chat_audio.js +73 -0
  2. data/app/assets/javascripts/chat_interface_manager.js.erb +197 -0
  3. data/app/assets/javascripts/chat_parser.js +243 -0
  4. data/app/assets/javascripts/chat_utilities.js +71 -0
  5. data/app/assets/javascripts/chat_window_manager.js +138 -0
  6. data/app/assets/javascripts/social_stream-presence.js +3 -0
  7. data/app/assets/javascripts/store.js +0 -7
  8. data/app/assets/javascripts/xmpp_client_management.js.erb +304 -0
  9. data/app/assets/stylesheets/chat.css +49 -3
  10. data/app/assets/stylesheets/social_stream-presence.css +1 -0
  11. data/app/controllers/xmpp_controller.rb +43 -9
  12. data/app/views/{xmpp/_chat_connecting.html.erb → chat/_connecting.html.erb} +0 -0
  13. data/app/views/{xmpp/_chat_contacts.html.erb → chat/_contacts.html.erb} +0 -0
  14. data/app/views/{xmpp/_chat.html.erb → chat/_index.html.erb} +3 -13
  15. data/app/views/{xmpp/_chat_off.html.erb → chat/_off.html.erb} +0 -0
  16. data/app/views/chat/_settings.html.erb +38 -0
  17. data/config/routes.rb +1 -1
  18. data/db/migrate/20111116194112_add_chat_enabled_column_to_user.rb +9 -0
  19. data/lib/social_stream/presence/version.rb +1 -1
  20. data/{app → vendor}/assets/javascripts/jquery.tools.tooltip.js +0 -0
  21. data/{app → vendor}/assets/javascripts/jquery.ui.chatbox.js +14 -12
  22. data/{app → vendor}/assets/javascripts/strophe.js +0 -0
  23. data/{app → vendor}/assets/stylesheets/jquery.ui.chatbox.css +0 -0
  24. metadata +19 -14
  25. data/app/assets/javascripts/jquery-ui-1.8.14.custom.min.js +0 -789
  26. data/app/assets/javascripts/jquery.tools.min.js +0 -17
  27. data/app/assets/javascripts/xmpp_client.js.erb +0 -925
@@ -0,0 +1,73 @@
1
+ ////////////////////
2
+ //Audio functions
3
+ ////////////////////
4
+
5
+ //Global audio variables
6
+ var onMessageAudio;
7
+
8
+ var html5_audiotypes=[
9
+ ["mp3","audio/mpeg"],
10
+ //["mp4","audio/mp4"],
11
+ //["ogg","audio/ogg"],
12
+ ["wav","audio/wav"]
13
+ ]
14
+
15
+ function initAudio(){
16
+ //Init all audio files
17
+ initSound("onMessageAudio");
18
+ }
19
+
20
+ function initSound(sound){
21
+
22
+ //Check support for HTML5 audio
23
+ var html5audio=document.createElement('audio')
24
+
25
+ if (html5audio.canPlayType){
26
+ path = 'assets/chat/' + sound;
27
+ window[sound] = new Audio();
28
+
29
+ for(i=0; i<html5_audiotypes.length; i++){
30
+ if (window[sound].canPlayType(html5_audiotypes[i][1])) {
31
+ var source= document.createElement('source');
32
+ source.type= html5_audiotypes[i][1];
33
+ source.src= path + '.' + html5_audiotypes[i][0];
34
+ window[sound].addEventListener('ended', endSoundListener);
35
+ window[sound].appendChild(source);
36
+ }
37
+ }
38
+ } else {
39
+ //Browser doesn't support HTML5 audio
40
+ }
41
+ }
42
+
43
+ function endSoundListener(){ }
44
+
45
+ function playSound(sound){
46
+ if (window[sound]!=null){
47
+ window[sound].play();
48
+ } else {
49
+ //Fallback option: When browser doesn't support HTML5 audio
50
+ $('body').append('<embed src="/' + sound + '.mp3" autostart="true" hidden="true" loop="false">');
51
+ }
52
+ }
53
+
54
+ function initAndPlaySound(sound){
55
+ initSound(sound);
56
+ playSound(sound);
57
+ }
58
+
59
+
60
+ function mustPlaySoundForChatWindow(chatBox){
61
+ //Deny conditions
62
+ if(userStatus == "dnd"){
63
+ return false;
64
+ }
65
+
66
+ //Accept conditions
67
+ if (!chatFocus){
68
+ return true;
69
+ }
70
+
71
+ //Default action
72
+ return false
73
+ }
@@ -0,0 +1,197 @@
1
+ ////////////////////
2
+ //Hash table
3
+ ////////////////////
4
+ var statusIcons = new Array();
5
+ statusIcons[''] = "available";
6
+ statusIcons['chat'] = "available";
7
+ statusIcons['away'] = "away";
8
+ statusIcons['xa'] = "away";
9
+ statusIcons['dnd'] = "dnd";
10
+
11
+
12
+ ////////////////////
13
+ //Reconnect button interface functions
14
+ ////////////////////
15
+
16
+ var connectButtonTimer;
17
+ var periodBetweenAttempts=15; //(seg)
18
+ var connectButtonTimerCounter=periodBetweenAttempts;
19
+
20
+ function connectButtonTimerFunction(){
21
+ if(connectButtonTimerCounter < periodBetweenAttempts){
22
+ connectButtonTimerCounter++;
23
+ } else if (connectButtonTimerCounter == periodBetweenAttempts) {
24
+ $("#chat_header_title").html('<%=I18n.t('chat.disconnected')%>')
25
+ }
26
+ }
27
+
28
+ function requestConnectToChat(){
29
+ if (connectButtonTimerCounter > (periodBetweenAttempts-1)) {
30
+ connectButtonTimerCounter=0;
31
+ $("#chat_header_title").html('<%=I18n.t('chat.connecting')%>')
32
+ return true
33
+ } else {
34
+ return false
35
+ }
36
+ }
37
+
38
+
39
+ ////////////////////
40
+ //Chat interface: Connection boxes
41
+ ////////////////////
42
+
43
+ function setUserFunctions(){
44
+
45
+ $("div.user_presence").click(function(event, ui){
46
+ var guest_name = $(this).attr("name");
47
+ var guest_slug = $(this).attr("slug");
48
+ var guest_jid = guest_slug + "@" + domain;
49
+
50
+ if (createChatBox(guest_slug, guest_name, guest_jid, user_name, user_jid)) {
51
+ } else {
52
+ window[getChatVariableFromSlug(guest_slug)].chatbox("option", "boxManager").toggleBox(true);
53
+ };
54
+ });
55
+
56
+
57
+ ////////////////////
58
+ //Chat interface: Status selector
59
+ ////////////////////
60
+
61
+ //JQuery DropdwanStatus
62
+
63
+ $(".dropdown dt a").click(function(event) {
64
+ event.preventDefault();
65
+ $(".dropdown dd ul").toggle();
66
+ });
67
+
68
+ $(".dropdown dd ul li a.option").click(function(event) {
69
+ event.preventDefault();
70
+ var text = $(this).html();
71
+ $(".dropdown dt a span").html(text);
72
+ userStatus = getSelectedValue("status");
73
+ sendStatus(userStatus);
74
+ $(".dropdown dd ul").hide();
75
+ });
76
+
77
+
78
+ function getSelectedValue(id) {
79
+ return $("#" + id).find("dt a span.value").html();
80
+ }
81
+
82
+ $(document).bind('click', function(e) {
83
+ var $clicked = $(e.target);
84
+ if (! $clicked.parents().hasClass("dropdown")){
85
+ //Click outside the select...
86
+ $(".dropdown dd ul").hide();
87
+ }
88
+ });
89
+ }
90
+
91
+
92
+ ////////////////////
93
+ //Away Timer Management
94
+ ////////////////////
95
+
96
+ function awayTimerFunction(){
97
+ awayCounter++;
98
+ if (awayCounter > (awayTime/awayTimerPeriod)){
99
+ userStatus = "away";
100
+ sendStatus(userStatus);
101
+ clearTimeout(awayTimer);
102
+ } else {
103
+ userStatus = "chat";
104
+ }
105
+ }
106
+
107
+ function resumeAwayTimerIfAway(){
108
+ if (userStatus == "away"){
109
+ awayCounter = 0;
110
+ userStatus = "chat";
111
+ sendStatus(userStatus);
112
+ awayTimer = setInterval("awayTimerFunction()", awayTimerPeriod);
113
+ }
114
+ }
115
+
116
+
117
+ ////////////////////
118
+ //Update chatWindow Management
119
+ ////////////////////
120
+
121
+ function timerFunction(){
122
+ timerCounter++;
123
+
124
+ if((timerCounter > cyclesToRefresh)&&(requestContacts)) {
125
+ requestContacts = false;
126
+ updateChatWindow();
127
+ }
128
+ }
129
+
130
+
131
+ function refreshChatWindow(){
132
+ if(timerCounter > cyclesToRefresh){
133
+ updateChatWindow();
134
+ } else {
135
+ requestContacts = true;
136
+ }
137
+ }
138
+
139
+
140
+ function updateChatWindow(){
141
+ timerCounter=0;
142
+ log("updateChatWindow()");
143
+ $.post("/chatWindow", { userConnected: userConnected }, function(data){
144
+ $(".tooltip").hide() //Prevent tooltips
145
+ $("#chat_partial").html(data);
146
+ if (userConnected) {
147
+ $(".user_presence a[title]").tooltip();
148
+ setUserFunctions();
149
+ }
150
+ });
151
+ }
152
+
153
+ function getConnectionBoxFromSlug(slug){
154
+ if ($('div.user_presence[slug=' + slug + ']').length > 0){
155
+ return ($('div.user_presence[slug=' + slug + ']'))[0];
156
+ } else {
157
+ return null;
158
+ }
159
+ }
160
+
161
+ var cacheConnectedUsers = [];
162
+ function hideConnectionBoxFromSlug(slug){
163
+ if ($('div.user_presence[slug=' + slug + ']').length > 0){
164
+ $('div.user_presence[slug=' + slug + ']').hide();
165
+ if(cacheConnectedUsers.indexOf(slug)==-1){
166
+ cacheConnectedUsers.push(slug);
167
+ }
168
+ }
169
+ }
170
+
171
+ function showConnectionBoxFromSlug(slug){
172
+ if ($('div.user_presence[slug=' + slug + ']').length > 0){
173
+ if (!($('div.user_presence[slug=' + slug + ']').is(":visible"))){
174
+ $('div.user_presence[slug=' + slug + ']').show();
175
+ }
176
+ }
177
+ }
178
+
179
+ function setUserIconStatus(slug, status){
180
+ if (status in statusIcons) {
181
+ iconName = statusIcons[status];
182
+ var $img_status = $('img.presence_status');
183
+ connectionBox = getConnectionBoxFromSlug(slug);
184
+ $(connectionBox).find($img_status).attr("src", "/assets/status/" + iconName + ".png")
185
+ }
186
+ }
187
+
188
+ function getAllConnectedSlugs(){
189
+ connectedSlugs=[];
190
+ connectionBoxes = $('div.user_presence[slug]');
191
+ $.each(connectionBoxes, function(index, value) {
192
+ if($(value).is(":visible")){
193
+ connectedSlugs.push($(value).attr("slug"))
194
+ }
195
+ });
196
+ return connectedSlugs
197
+ }
@@ -0,0 +1,243 @@
1
+ ////////////////////
2
+ //Hash table
3
+ ////////////////////
4
+ var chatIcons = new Array();
5
+ chatIcons[':)'] = "face-smile.png";
6
+ chatIcons[':('] = "face-sad.png";
7
+ chatIcons['(B)'] = "beer.png";
8
+ chatIcons['(C)'] = "clock.png";
9
+ chatIcons['(P)'] = "present.png";
10
+ chatIcons[':P']= "face-raspberry.png";
11
+ chatIcons[':Z']= "face-tired.png";
12
+ chatIcons['(R)']= "rain.png";
13
+ chatIcons['(S)']= "sun.png";
14
+ chatIcons[';)']= "face-wink.png";
15
+
16
+ ///////////////////////////////////////////////////////
17
+ // Parser functions
18
+ // Allow new features in chat msg like links, images, emoticons, ...
19
+ ///////////////////////////////////////////////////////
20
+
21
+ //Patterns
22
+ var html_tag_pattern=/.*\<[^>]+>.*/g
23
+ var simple_word_pattern=/^[aA-zZ0-9]+$/g
24
+ var http_urls_pattern=/(http(s)?:\/\/)([aA-zZ0-9%=_&+?])+([./-][aA-zZ0-9%=_&+?]+)*[/]?/g
25
+ var www_urls_pattern = /(www[.])([aA-zZ0-9%=_&+?])+([./-][aA-zZ0-9%=_&+?]+)*[/]?/g
26
+ var icons_a_pattern=/\([A-Z]\)/g
27
+ var icons_b_pattern=/((:|;)([()A-Z]))/g
28
+ var youtube_video_pattern=/(http(s)?:\/\/)?(((youtu.be\/)([aA-zZ0-9]+))|((www.youtube.com\/watch\?v=)([aA-z0-9Z&=.])+))/g
29
+
30
+
31
+ function getParsedContent(content,fromUser){
32
+ if (fromUser){
33
+ var chatTextclass = "ownChatText"
34
+ } else {
35
+ var chatTextclass = "guestChatText"
36
+ }
37
+ return ("<span class=\"" + chatTextclass + "\">" + parseContent(content) + "</span>");
38
+ }
39
+
40
+
41
+ function parseContent(content){
42
+
43
+ if (content.match(html_tag_pattern)!=null){
44
+ content = content.replace(/>/g, "&gt;");
45
+ content = content.replace(/</g, "&lt;");
46
+ return "<pre>" + content + "</pre>"
47
+ }
48
+
49
+ words = content.split(" ");
50
+ for(i=0; i<words.length; i++){
51
+ words[i] = parseWord(words[i]);
52
+ }
53
+
54
+ return words.join(" ");
55
+ }
56
+
57
+ function parseWord(word){
58
+
59
+ //Look for empty or simple words
60
+ if ((word.trim()=="")||(word.match(simple_word_pattern)!=null)){
61
+ return word
62
+ }
63
+
64
+ //Look for http urls
65
+ var http_urls = word.match(http_urls_pattern)
66
+ if (http_urls!=null){
67
+ var url = http_urls[0]
68
+ var type = getUrlType(url);
69
+
70
+ switch(type){
71
+ case "link":
72
+ var link = buildUrlLink(url,url)
73
+ var subwords = splitFirst(word,url)
74
+ return parseWord(subwords[0]) + link + parseWord(subwords[1])
75
+ case "image":
76
+ var imageLink = buildImageLink(url);
77
+ var subwords = splitFirst(word,url)
78
+ return parseWord(subwords[0]) + imageLink + parseWord(subwords[1])
79
+ case "video-youtube":
80
+ var youtubeLink = buildYoutubeVideoLink(url);
81
+ var subwords = splitFirst(word,url)
82
+ return parseWord(subwords[0]) + youtubeLink + parseWord(subwords[1])
83
+ default:
84
+ return word
85
+ }
86
+ }
87
+
88
+
89
+ //Look for www urls
90
+ var www_urls = word.match(www_urls_pattern)
91
+ if (www_urls!=null){
92
+ var url = www_urls[0]
93
+ var type = getUrlType(url);
94
+
95
+ switch(type){
96
+ case "link":
97
+ var link = buildUrlLink("http://" + url,url)
98
+ var subwords = splitFirst(word,url)
99
+ return parseWord(subwords[0]) + link + parseWord(subwords[1])
100
+ case "image":
101
+ var imageLink = buildImageLink("http://" + url);
102
+ var subwords = splitFirst(word,url)
103
+ return parseWord(subwords[0]) + imageLink + parseWord(subwords[1])
104
+ case "video-youtube":
105
+ var youtubeLink = buildYoutubeVideoLink("http://" + url);
106
+ var subwords = splitFirst(word,url)
107
+ return parseWord(subwords[0]) + youtubeLink + parseWord(subwords[1])
108
+ default:
109
+ return word
110
+ }
111
+ }
112
+
113
+ //Look for icons: Regex
114
+ var icons_a = word.match(icons_a_pattern)
115
+ if(icons_a!=null){
116
+ for(g=0; g<icons_a.length; g++){
117
+ word = word.replace(buildRegex(icons_a[g]), buildIconImage(icons_a[g]))
118
+ }
119
+ }
120
+
121
+ var icons_b = word.match(icons_b_pattern)
122
+ if(icons_b!=null){
123
+ for(h=0; h<icons_b.length; h++){
124
+ word = word.replace(buildRegex(icons_b[h]), buildIconImage(icons_b[h]))
125
+ }
126
+ }
127
+
128
+
129
+ //No special content detected (maybe emoticons but not special pattern like urls)
130
+ return word
131
+ }
132
+
133
+ function splitFirst(word,key){
134
+ split=[]
135
+ cut = word.split(key);
136
+ split[0]=cut[0]
137
+ cut.shift()
138
+ paste = cut.join(key)
139
+ split[1]=paste
140
+ return split
141
+ }
142
+
143
+ function buildIconImage(icon){
144
+ if (icon in chatIcons){
145
+ image_file = chatIcons[icon]
146
+ return "<img class=\"chatEmoticon\" src=\"assets/emoticons/" + image_file + "\"/>";
147
+ }
148
+ return icon
149
+ }
150
+
151
+ function buildUrlLink(url,name){
152
+ return "<a target=\"_blank\" class=\"chatLink\" href=\"" + url + "\">" + name + "</a>";
153
+ }
154
+
155
+ function buildImageLink(url){
156
+ return "<a target=\"_blank\" class=\"chatImageLink\" href=\"" + url + "\">" + "<img class=\"chatImage\" src=\"" + url + "\"/>" + "</a>";
157
+ }
158
+
159
+ function buildYoutubeVideoLink(url){
160
+ //Get youtube video id
161
+ var youtube_video_id=url.split(/v\/|v=|youtu\.be\//)[1].split(/[?&]/)[0];
162
+ var youtube_api_url = "http://gdata.youtube.com/feeds/api/videos/" + youtube_video_id
163
+
164
+ //Get info from the video
165
+ $.ajax({
166
+ type: "GET",
167
+ url: youtube_api_url,
168
+ cache: false,
169
+ dataType:'jsonp',
170
+ success: function(data){
171
+ var url_name = url;
172
+ var youtube_video_thumbnail = "";
173
+
174
+ //Video title
175
+ var video_title = $(data).find("media\\:title")
176
+ if (video_title.length > 0) {
177
+ //url_name = url + " (" + $(video_title).text() + ")";
178
+ url_name = $(video_title).text()
179
+ }
180
+
181
+ //Thumbnails
182
+ var thumbnails = $(data).find("media\\:thumbnail")
183
+ if (thumbnails.length>0){
184
+ var thumbnail_url = $(thumbnails[0]).attr("url")
185
+ if (thumbnail_url!=null){
186
+ youtube_video_thumbnail = "<p><img class=\"chatVideoImage\" src=\"" + thumbnail_url + "\"/></p>";
187
+ }
188
+ }
189
+
190
+ //Replace video link
191
+ $("a[youtube_id=" + youtube_video_id + "]").html(buildUrlLink(url,url_name)+youtube_video_thumbnail);
192
+ },
193
+ error: function(xOptions, textStatus){
194
+ //Handle errors
195
+ }
196
+ });
197
+
198
+ return "<a target=\"_blank\" youtube_id=\"" + youtube_video_id + "\" class=\"chatLink\" href=\"" + url + "\">" + url + "</a>";
199
+ }
200
+
201
+ function buildRegex(word){
202
+ word = word.replace(")","\\)")
203
+ word = word.replace("(","\\(")
204
+ var pattern = "(" + word + ")";
205
+ pattern = buildPattern(pattern)
206
+ return (new RegExp(pattern,'g'));
207
+ }
208
+
209
+ function buildPattern(pattern){
210
+ //Escape pattern special characters
211
+ pattern = pattern.replace("+","\\+")
212
+ pattern = pattern.replace("?","\\?")
213
+ return pattern
214
+ }
215
+
216
+
217
+ function getUrlType(url){
218
+
219
+ if (url.match(youtube_video_pattern)!=null){
220
+ return "video-youtube"
221
+ }
222
+
223
+ var urlArray = url.split(".");
224
+ if (urlArray!=null && urlArray.length>0){
225
+ var extension= urlArray[urlArray.length-1]
226
+ } else {
227
+ var extension = null;
228
+ }
229
+
230
+ switch(extension){
231
+ case "jpg":
232
+ return "image"
233
+ break;
234
+ case "png":
235
+ return "image"
236
+ break;
237
+ case "gif":
238
+ return "image"
239
+ break;
240
+ default:
241
+ return "link"
242
+ }
243
+ }