diff --git a/README.md b/README.md index ee79efa..69cd5ed 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,8 @@ To configure the chat, just use the object passed on IASChat instantiation. *Bol - defaultSupportPic: String Default support picture (if no supporter assigned) - uploadFiles: Boolean Enable or disable the option to upload and send files (Default: true) - onlyPictures: Boolean Allow only pictures, or all file types (Default: true) + - onMessage: Function Execute a function on message recieved. Params message (all object) and key are passed to the function + - onSend: Function Execute a function when a message is sent. Params message (all object) and key are passed to the function In IASChatProvider, there are some extra features: - container: String Container for support panel (*#identifier* or *.className*. Default: *body*) diff --git a/demo/index.html b/demo/index.html index 0edf122..4954338 100644 --- a/demo/index.html +++ b/demo/index.html @@ -61,8 +61,22 @@

User side support

mainColor: '#ff9800', textColor: '#fff', defaultSupportName: 'John Doe', - defaultSupportPic: 'http://lorempixel.com/100/100/people' + defaultSupportPic: 'http://lorempixel.com/100/100/people', + onMessage: myFunction, + onSend: function(msg, key) { + console.log('#################'); + console.log('- Message sent! Key: ' + key); + console.log(msg) + console.log('#################'); + } }); + + function myFunction(message, key) { + console.log('--------------------'); + console.log('- We got a message! key: ' + key); + console.log(message); + console.log('--------------------'); + } }; diff --git a/dist/chat.js b/dist/chat.js index 371fa41..03504ea 100644 --- a/dist/chat.js +++ b/dist/chat.js @@ -21,12 +21,15 @@ function IASChat(config) { var hashSign = config.hashSign || '?'; var uploadFiles = config.uploadFiles || true; var onlyPictures = config.onlyPictures || true; + var onSend = config.onSend || null; + var onMessage = config.onMessage || null; // Prepare interface printInterface(container); // Prepare listeners var show = document.getElementById('ias-show'); + var showNotifications = document.getElementById('ias-show-notifications'); var ias = document.getElementById('ias'); var topbar = document.getElementById('ias_topbar'); var close = document.getElementById('ias_topbar-close'); @@ -47,6 +50,10 @@ function IASChat(config) { var lastHash = ''; var lastPage = ''; + var user = null; + var lastMessage = {}; + + // Listen event submit if(show) { show.addEventListener('click', showIAS.bind(this)); @@ -83,7 +90,19 @@ function IASChat(config) { name = config.name || ''; pic = config.pic || ''; - setChatData(); + // Get chat info + userRef = firebase.database().ref('users/' + cid); + userRef.on('value', function(data) { + + user = data.val(); + + lastMessage = user.lastMessage; + // console.log(lastMessage); + + setChatData(); + setNotifications(); + }); + clearMessages(); @@ -96,10 +115,7 @@ function IASChat(config) { function setChatData() { - userRef = firebase.database().ref('users/' + cid); - userRef.on('value', function(data) { - var key = data.key; - var user = data.val(); + if(user) { var printData = { name: defaultSupportName, @@ -118,8 +134,9 @@ function IASChat(config) { document.getElementById('ias_topbar-text').innerHTML = printData.name; document.getElementById('ias_topbar-pic').firstChild.setAttribute('src', printData.pic); - }); - + } else { + setTimeout(setChatData, 100); + } } @@ -131,11 +148,11 @@ function IASChat(config) { // If shall show button, add it to interface (from html/show-button.html) if(button) { - ias += '
' + ias += '
' } // Also add the styles from css/style.css - ias += ''; + ias += ''; var printplace = null; @@ -219,7 +236,7 @@ function IASChat(config) { var text = e.srcElement.children[1].value if(text === '' && attatchment === null) { - console.log('tried to send empty form. Rejected.'); + console.warn('tried to send empty form. Rejected.'); return false; } @@ -278,6 +295,10 @@ function IASChat(config) { firebase.database().ref('messages/' + cid).push(msg); firebase.database().ref('users/' + cid).once('value').then(function(snapshot) { + + var userLastMsg = msg; + userLastMsg.read = false; + if(!snapshot.val()) { // Add user firebase.database().ref('users/' + cid).set({ @@ -285,10 +306,10 @@ function IASChat(config) { pic: pic, isSupporter: false, supporter: -1, - lastMessage: msg + lastMessage: userLastMsg }); } else { - firebase.database().ref('users/' + cid).update({lastMessage: msg}); + firebase.database().ref('users/' + cid).update({lastMessage: userLastMsg}); if(!snapshot.val().profile) { generateUserData(cid) } @@ -312,8 +333,44 @@ function IASChat(config) { if(message.uid == uid) { printMessage(text); + if(typeof onSend === 'function' && message.timestamp > lastMessage.timestamp) { + onSend(message, key); + } } else { printMessage(text, true); + + // If chat is open, set the message as read + if(!isHidden()) { + readLastMessage(); + } + + if(typeof onMessage === 'function' && message.timestamp > lastMessage.timestamp) { + onMessage(message, key); + } + } + } + + function readLastMessage() { + firebase.database().ref('users/' + cid + '/lastMessage').update({read: true}); + } + + function setNotifications() { + + // Only set notifications if button are enabled + if(button) { + if(lastMessage.uid !== uid && !lastMessage.read) { + if (showNotifications.classList) { + showNotifications.classList.remove('hidden'); + } else { + showNotifications.className = showNotifications.className.replace(new RegExp('(^|\\b)' + 'hidden'.split(' ').join('|') + '(\\b|$)', 'gi'), ' '); + } + } else { + if (showNotifications.classList) { + showNotifications.classList.add('hidden'); + } else { + showNotifications.className += ' ' + 'hidden'; + } + } } } @@ -338,6 +395,9 @@ function IASChat(config) { // Also set url hash to true; addUrlHash(); + + // And read last message + readLastMessage(); } function hideIAS(e) { @@ -355,6 +415,20 @@ function IASChat(config) { remUrlHash(); } + function isHidden(e) { + if(typeof(e) !== 'undefined') { + e.preventDefault(); + } + + var className = 'hidden'; + + if (ias.classList) { + return ias.classList.contains(className); + } else { + return new RegExp('(^| )' + className + '( |$)', 'gi').test(ias.className); + } + } + /* ### URL Hash ### */ function visibilityUrlHash() { diff --git a/dist/provider.js b/dist/provider.js index d60947e..ec7e684 100644 --- a/dist/provider.js +++ b/dist/provider.js @@ -49,7 +49,7 @@ function IASChatProvider(config) { function printInterface(container) { // Compressed version of html/chat.html turned to string - var ias = '

Unassigned Users:

Your Users:

' + var ias = '

Unassigned Users:

Your Users:

' // Also add the provider styles from css/provider-style.css // ias += ''; @@ -101,10 +101,25 @@ function IASChatProvider(config) { var supporter = data.supporter.uid || data.supporter; + var read = true; + + if(typeof data.lastMessage !== 'undefined' && typeof data.lastMessage.read !== 'undefined' && !data.lastMessage.read) { + read = false; + } + var user = document.createElement('li'); user.setAttribute("data-cid", data.uid); user.setAttribute("data-supporter", supporter); + + if(read) { user.innerHTML = '
' + data.name + '
'; + } else { + var message = data.lastMessage.text; + if(data.lastMessage.text.length > 20) + message = data.lastMessage.text.slice(0, 20) + '...'; + + user.innerHTML = '
' + data.name + '
' + message + '
'; + } user.addEventListener('click', usersChatManagement, false); diff --git a/js/chat.js b/js/chat.js index ac0a7e1..a7f7c75 100644 --- a/js/chat.js +++ b/js/chat.js @@ -21,12 +21,15 @@ function IASChat(config) { var hashSign = config.hashSign || '?'; var uploadFiles = config.uploadFiles || true; var onlyPictures = config.onlyPictures || true; + var onSend = config.onSend || null; + var onMessage = config.onMessage || null; // Prepare interface printInterface(container); // Prepare listeners var show = document.getElementById('ias-show'); + var showNotifications = document.getElementById('ias-show-notifications'); var ias = document.getElementById('ias'); var topbar = document.getElementById('ias_topbar'); var close = document.getElementById('ias_topbar-close'); @@ -47,6 +50,10 @@ function IASChat(config) { var lastHash = ''; var lastPage = ''; + var user = null; + var lastMessage = {}; + + // Listen event submit if(show) { show.addEventListener('click', showIAS.bind(this)); @@ -83,7 +90,19 @@ function IASChat(config) { name = config.name || ''; pic = config.pic || ''; - setChatData(); + // Get chat info + userRef = firebase.database().ref('users/' + cid); + userRef.on('value', function(data) { + + user = data.val(); + + lastMessage = user.lastMessage; + // console.log(lastMessage); + + setChatData(); + setNotifications(); + }); + clearMessages(); @@ -96,10 +115,7 @@ function IASChat(config) { function setChatData() { - userRef = firebase.database().ref('users/' + cid); - userRef.on('value', function(data) { - var key = data.key; - var user = data.val(); + if(user) { var printData = { name: defaultSupportName, @@ -118,8 +134,9 @@ function IASChat(config) { document.getElementById('ias_topbar-text').innerHTML = printData.name; document.getElementById('ias_topbar-pic').firstChild.setAttribute('src', printData.pic); - }); - + } else { + setTimeout(setChatData, 100); + } } @@ -219,7 +236,7 @@ function IASChat(config) { var text = e.srcElement.children[1].value if(text === '' && attatchment === null) { - console.log('tried to send empty form. Rejected.'); + console.warn('tried to send empty form. Rejected.'); return false; } @@ -278,6 +295,10 @@ function IASChat(config) { firebase.database().ref('messages/' + cid).push(msg); firebase.database().ref('users/' + cid).once('value').then(function(snapshot) { + + var userLastMsg = msg; + userLastMsg.read = false; + if(!snapshot.val()) { // Add user firebase.database().ref('users/' + cid).set({ @@ -285,10 +306,10 @@ function IASChat(config) { pic: pic, isSupporter: false, supporter: -1, - lastMessage: msg + lastMessage: userLastMsg }); } else { - firebase.database().ref('users/' + cid).update({lastMessage: msg}); + firebase.database().ref('users/' + cid).update({lastMessage: userLastMsg}); if(!snapshot.val().profile) { generateUserData(cid) } @@ -312,8 +333,44 @@ function IASChat(config) { if(message.uid == uid) { printMessage(text); + if(typeof onSend === 'function' && message.timestamp > lastMessage.timestamp) { + onSend(message, key); + } } else { printMessage(text, true); + + // If chat is open, set the message as read + if(!isHidden()) { + readLastMessage(); + } + + if(typeof onMessage === 'function' && message.timestamp > lastMessage.timestamp) { + onMessage(message, key); + } + } + } + + function readLastMessage() { + firebase.database().ref('users/' + cid + '/lastMessage').update({read: true}); + } + + function setNotifications() { + + // Only set notifications if button are enabled + if(button) { + if(lastMessage.uid !== uid && !lastMessage.read) { + if (showNotifications.classList) { + showNotifications.classList.remove('hidden'); + } else { + showNotifications.className = showNotifications.className.replace(new RegExp('(^|\\b)' + 'hidden'.split(' ').join('|') + '(\\b|$)', 'gi'), ' '); + } + } else { + if (showNotifications.classList) { + showNotifications.classList.add('hidden'); + } else { + showNotifications.className += ' ' + 'hidden'; + } + } } } @@ -338,6 +395,9 @@ function IASChat(config) { // Also set url hash to true; addUrlHash(); + + // And read last message + readLastMessage(); } function hideIAS(e) { @@ -355,6 +415,20 @@ function IASChat(config) { remUrlHash(); } + function isHidden(e) { + if(typeof(e) !== 'undefined') { + e.preventDefault(); + } + + var className = 'hidden'; + + if (ias.classList) { + return ias.classList.contains(className); + } else { + return new RegExp('(^| )' + className + '( |$)', 'gi').test(ias.className); + } + } + /* ### URL Hash ### */ function visibilityUrlHash() { diff --git a/js/provider.js b/js/provider.js index 297e5ee..2012049 100644 --- a/js/provider.js +++ b/js/provider.js @@ -101,10 +101,25 @@ function IASChatProvider(config) { var supporter = data.supporter.uid || data.supporter; + var read = true; + + if(typeof data.lastMessage !== 'undefined' && typeof data.lastMessage.read !== 'undefined' && !data.lastMessage.read) { + read = false; + } + var user = document.createElement('li'); user.setAttribute("data-cid", data.uid); user.setAttribute("data-supporter", supporter); + + if(read) { user.innerHTML = '
' + data.name + '
'; + } else { + var message = data.lastMessage.text; + if(data.lastMessage.text.length > 20) + message = data.lastMessage.text.slice(0, 20) + '...'; + + user.innerHTML = '
' + data.name + '
' + message + '
'; + } user.addEventListener('click', usersChatManagement, false); diff --git a/template/ias_provider.html b/template/ias_provider.html index 78a12e9..3153c4c 100644 --- a/template/ias_provider.html +++ b/template/ias_provider.html @@ -21,6 +21,15 @@

Your Users:

padding: 0; } + .iasProvider_users-chat-unread { + font-weight: bold; + } + + .iasProvider_users-chat-message { + font-weight: lighter; + font-family: .8em; + } + .iasProvider_users-chat li div { display: inline-block; vertical-align: middle; diff --git a/template/ias_segment.html b/template/ias_segment.html index 631c940..02a2f06 100644 --- a/template/ias_segment.html +++ b/template/ias_segment.html @@ -3,4 +3,5 @@ + \ No newline at end of file diff --git a/template/ias_style.html b/template/ias_style.html index f46eb6a..71b99ea 100644 --- a/template/ias_style.html +++ b/template/ias_style.html @@ -151,6 +151,18 @@ right: 16px; width: 56px; } + #ias-show-notifications { + height: 16px; + width: 16px; + background: red; + position: absolute; + left: 1px; + top: 1px; + border-radius: 50%; + } + #ias-show-notifications.hidden { + display: none; + } @media screen and (min-width: 842px) { #ias {