From 31c4faab05efb29ba5335964c9012fd9d3fa15bb Mon Sep 17 00:00:00 2001 From: "A. Hoyt" Date: Wed, 6 Mar 2019 14:46:07 -0500 Subject: [PATCH 01/24] Baseline --- application.py | 3 +++ static/Index.js | 34 ++++++++++++++++++++++++++++++++++ templates/index.html | 25 +++++++++++++++++++++++++ 3 files changed, 62 insertions(+) create mode 100644 static/Index.js create mode 100644 templates/index.html diff --git a/application.py b/application.py index e8edb33..ce3dbe1 100644 --- a/application.py +++ b/application.py @@ -11,3 +11,6 @@ @app.route("/") def index(): return "Project 2: TODO" + +if __name__ == '__main__': + app.run() \ No newline at end of file diff --git a/static/Index.js b/static/Index.js new file mode 100644 index 0000000..d540ca4 --- /dev/null +++ b/static/Index.js @@ -0,0 +1,34 @@ +// This code does not work! +// please watch section video for explanation of what was typed +// THIS CODE DOES NOT WORK + + +document.addEventListener('DOMContentLoaded', () => { + + // Connect to websocket + var socket = io.connect(location.protocol + '//' + document.domain + ':' + location.port); + + // When connected, configure buttons + socket.on('connect', () => { + + // Each button should emit a "submit vote" event + document.querySelector('create-channel').onclick = () => { + const name = document.querySelector('input[name]').value; + socket.emit('create-channel', {'name': name}); + }; + + // Each button should emit a "submit vote" event + document.querySelector('new-message').onclick = () => { + // Get the channel + // Get the message + socket.emit('send-message', {'channel': channel, 'msg': msg}); + }; + }); + + // When a new vote is announced, add to the unordered list + socket.on('vote totals', data => { + document.querySelector('#yes').innerHTML = data.yes; + document.querySelector('#no').innerHTML = data.no; + document.querySelector('#maybe').innerHTML = data.maybe; + }); +}); \ No newline at end of file diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..a7cbb63 --- /dev/null +++ b/templates/index.html @@ -0,0 +1,25 @@ + + + + + + + + Vote + + +
Yes Votes: {{ votes["yes"] }}
+
No Votes: {{ votes["no"] }}
+
Maybe Votes: {{ votes["maybe"] }}
+
+ + + + + + + + + \ No newline at end of file From 88ba53f2163f7d907ec544b154f61f9c9506fd94 Mon Sep 17 00:00:00 2001 From: "A. Hoyt" Date: Fri, 15 Mar 2019 00:26:34 -0400 Subject: [PATCH 02/24] Updating baseline - created skeleton website and tweaked the layout --- README.md | 5 +++ application.py | 9 +++-- static/FlackUser.png | Bin 0 -> 12987 bytes static/Index.js | 41 +++++++++++++++++++-- static/addChannel.png | Bin 0 -> 9720 bytes static/style.css | 83 ++++++++++++++++++++++++++++++++++++++++++ templates/index.html | 69 +++++++++++++++++++++++++---------- 7 files changed, 180 insertions(+), 27 deletions(-) create mode 100644 static/FlackUser.png create mode 100644 static/addChannel.png create mode 100644 static/style.css diff --git a/README.md b/README.md index 2a97a3f..aa38731 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,8 @@ # Project 2 Web Programming with Python and JavaScript + +1) User must not block pop-ups from their browser - the application uses prompts to query for a username and stores the value locally +2) The user name is displayed at the top of the Flack screen +3) To add channels select the plus (+) icon next to "Channels" + \ No newline at end of file diff --git a/application.py b/application.py index ce3dbe1..006abb7 100644 --- a/application.py +++ b/application.py @@ -1,16 +1,19 @@ import os -from flask import Flask +from flask import Flask, render_template, redirect, request from flask_socketio import SocketIO, emit app = Flask(__name__) app.config["SECRET_KEY"] = os.getenv("SECRET_KEY") socketio = SocketIO(app) - @app.route("/") +@app.route('/index') def index(): - return "Project 2: TODO" + print("Loading index.html..") + return render_template('index.html', votes=True) + + if __name__ == '__main__': app.run() \ No newline at end of file diff --git a/static/FlackUser.png b/static/FlackUser.png new file mode 100644 index 0000000000000000000000000000000000000000..2fb1da6164abf0053ec9eac5ea3ff822ec0970b9 GIT binary patch literal 12987 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 X_0)@eU4S5NF#s(!ebowOyYT-9w-t!A literal 0 HcmV?d00001 diff --git a/static/Index.js b/static/Index.js index d540ca4..bef6984 100644 --- a/static/Index.js +++ b/static/Index.js @@ -1,8 +1,40 @@ -// This code does not work! -// please watch section video for explanation of what was typed -// THIS CODE DOES NOT WORK +//document.addEventListener('DOMContentLoaded', ()=> { +// document.querySelector('#form').onsubmit = () => { +// const name = document.querySelector('#name').value; +// alert(`Hello ${name}!`); +// }; +//}); +var username; +// prompt user via popup to enter a username that we can use for Flack +function getUsername() { + // can't give us an empty response - will keep prompting until not empty + while (!username) { + username = prompt("Enter a Username: ", ""); + if (!username) { + alert("Username not found - you must enter a username to use this site!"); + } else { + return username; + } + } +} +// was document.getElementById("user").innerHTML = +// user names stored locally via browser - is not there we prompt for one +function loadUsername() { + // Have we stored a username before + if (!localStorage.getItem('username')) + localStorage.setItem('username', getUsername()); + console.log(username); + // Load current username + document.addEventListener('DOMContentLoaded', () => { + document.querySelector('#user').innerHTML = "Flask: "+localStorage.getItem('username'); + }); +} + +loadUsername() + +/* document.addEventListener('DOMContentLoaded', () => { // Connect to websocket @@ -31,4 +63,5 @@ document.addEventListener('DOMContentLoaded', () => { document.querySelector('#no').innerHTML = data.no; document.querySelector('#maybe').innerHTML = data.maybe; }); -}); \ No newline at end of file +}); +*/ \ No newline at end of file diff --git a/static/addChannel.png b/static/addChannel.png new file mode 100644 index 0000000000000000000000000000000000000000..dcdcf08cae1917498af1457f4a9abb5053b5887d GIT binary patch literal 9720 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 - - - - - Vote - - -
Yes Votes: {{ votes["yes"] }}
-
No Votes: {{ votes["no"] }}
-
Maybe Votes: {{ votes["maybe"] }}
-
- - - + + + + + + + - - + + - + Flack + + + + +
+
+ + + + + +
Channels
+
+
    +
    +
  • # channel 1
  • +
  • # channel 2
  • +
+
Flack
+
+
    +
  • message 1
  • +
  • message 2
  • +
  • +
  • +
  • +
  • +
  • +
  • +
  • +
  • +
+
+
+ +
+
+ \ No newline at end of file From 19cb8b7b42ecc995ac13aa9335649ce17f6a09e8 Mon Sep 17 00:00:00 2001 From: "A. Hoyt" Date: Wed, 20 Mar 2019 23:33:11 -0400 Subject: [PATCH 03/24] Updating baseline again - working through issues, javascript and html changes --- README.md | 2 +- application.py | 68 +++++++++++++++++-- static/FlackUser.png | Bin 12987 -> 1069 bytes static/Index.js | 135 +++++++++++++++++++++++++------------- static/addChannel.png | Bin 9720 -> 0 bytes static/addGraphic.png | Bin 0 -> 1767 bytes static/favicon.ico | Bin 0 -> 1069 bytes static/style.css | 81 +---------------------- templates/index.html | 148 +++++++++++++++++++++++++++--------------- 9 files changed, 252 insertions(+), 182 deletions(-) delete mode 100644 static/addChannel.png create mode 100644 static/addGraphic.png create mode 100644 static/favicon.ico diff --git a/README.md b/README.md index aa38731..a1347f3 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Project 2 +# Project 2 README.md file Web Programming with Python and JavaScript diff --git a/application.py b/application.py index 006abb7..9fde1ef 100644 --- a/application.py +++ b/application.py @@ -1,19 +1,75 @@ import os -from flask import Flask, render_template, redirect, request +from flask import Flask, render_template, redirect, request, jsonify, request, flash, url_for, session from flask_socketio import SocketIO, emit app = Flask(__name__) + +# Configure to use filesystem session type app.config["SECRET_KEY"] = os.getenv("SECRET_KEY") +app.config["SESSION_PERMANENT"] = False +app.config["SESSION_TYPE"] = "filesystem" + socketio = SocketIO(app) +app.secret_key = os.urandom(32) +# Session(app) + +# Global lists and dicts +channels = [] +messages = {} +users = {} + +MESSAGELIMIT = 100 @app.route("/") -@app.route('/index') +@app.route("/index") def index(): - print("Loading index.html..") - return render_template('index.html', votes=True) + return render_template("index.html") + +@socketio.on('user connect') +def connect(data): + + # check if user already connected + if (data["username"] not in users.values()): + + # if users{} empty - first time through + if not users: + users.update({0: data["username"]}) + else: + # determine next dict key and increment + dictKeys = list(users.keys()) + nextKey = max(dictKeys)+1 + users.update({nextKey: data["username"]}) + + emit("new user", users, broadcast=True) + print(users) + + # check if already registered - avoid duplicates + # data = {0: 'sandeep', 1: 'glasknicoff', 2: 'mordor'} + # print("number: "+data.get(key,0)+1) + # print(data) + # emit("new user", data, broadcast=True) + + +@socketio.on('new-channel') +def addChannel(data): + channel = data["selection"] + print("new-channel for: "+ channel) + results = {"success": True, "channel": channel} + emit("announce channel", results, broadcast=True) +@socketio.on('debug') +def debug(data): +# print("debug message: ", data["message"]) + channel = data["message"] + print("debug from server, for: "+ channel) + results = {"success": True, "channel": channel} + emit("announce channel", results, broadcast=True) -if __name__ == '__main__': - app.run() \ No newline at end of file +@socketio.on('send-message') +def addChannel(data): + channel = data["selection"] + print("send-message for: "+ channel) + results = {"success": True, "channel": channel} + emit("announce channel", results, broadcast=True) \ No newline at end of file diff --git a/static/FlackUser.png b/static/FlackUser.png index 2fb1da6164abf0053ec9eac5ea3ff822ec0970b9..1b41190c17b978bdd5e7432b5b668769d594bc37 100644 GIT binary patch literal 1069 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 X_0)@eU4S5NF#s(!ebowOyYT-9w-t!A diff --git a/static/Index.js b/static/Index.js index bef6984..6dcf36e 100644 --- a/static/Index.js +++ b/static/Index.js @@ -1,16 +1,19 @@ -//document.addEventListener('DOMContentLoaded', ()=> { -// document.querySelector('#form').onsubmit = () => { -// const name = document.querySelector('#name').value; -// alert(`Hello ${name}!`); -// }; -//}); +// connect to websocket +var socket = io.connect(location.protocol + '//' + document.domain + ':' + location.port); +// globals var username; -// prompt user via popup to enter a username that we can use for Flack +var userList = []; +var channelList = []; + +loadUsername(); + +// prompt user via popup to enter a username before using Flack function getUsername() { - // can't give us an empty response - will keep prompting until not empty + + // can't give an empty response - keep prompting until not empty while (!username) { - username = prompt("Enter a Username: ", ""); + username = prompt("Enter a username for Flack: ", ""); if (!username) { alert("Username not found - you must enter a username to use this site!"); } else { @@ -18,50 +21,94 @@ function getUsername() { } } } -// was document.getElementById("user").innerHTML = -// user names stored locally via browser - is not there we prompt for one +// check if username stored locally - if not there, we prompt for one function loadUsername() { - // Have we stored a username before - if (!localStorage.getItem('username')) - localStorage.setItem('username', getUsername()); - console.log(username); - // Load current username - document.addEventListener('DOMContentLoaded', () => { - document.querySelector('#user').innerHTML = "Flask: "+localStorage.getItem('username'); - }); -} -loadUsername() + // have we stored a username before + if (!localStorage.getItem('username')) { + username = getUsername(); + localStorage.setItem('username', username ); + socket.emit('user connect', {'username': username}); + } else { + username = localStorage.getItem('username'); + socket.emit('user connect', {'username': username}); + } +} -/* document.addEventListener('DOMContentLoaded', () => { - // Connect to websocket - var socket = io.connect(location.protocol + '//' + document.domain + ':' + location.port); - - // When connected, configure buttons + // when connectedl, start the heavy lifting socket.on('connect', () => { - // Each button should emit a "submit vote" event - document.querySelector('create-channel').onclick = () => { - const name = document.querySelector('input[name]').value; - socket.emit('create-channel', {'name': name}); - }; - - // Each button should emit a "submit vote" event - document.querySelector('new-message').onclick = () => { - // Get the channel - // Get the message - socket.emit('send-message', {'channel': channel, 'msg': msg}); - }; + //document.getElementById("message").addEventListener("click", () => { + // const selection = button.dataset.message; //get like document.querySelector('#channel').value; + // socket.emit('send-message', {'selection': "CHANNEL"}); // send-message w/ dict multiple elements + //}); + // Adding a new channel + //document.querySelector('#form').onsubmit = ()=> { + + +// +// const selection = document.querySelector('#channel').value; +// socket.emit('new-channel', {'selection': selection}); // should be create or add-channel: channelName +// socket.emit('debug', {'message': selection}); +// }; + + }); + + // Add channel to the unordered channel list - used for testing + socket.on('channel list', data => { + + console.log("Processing server response..."); + const contents = `${data.channel}`; + + // Create new channel item for list + const li = document.createElement('li'); + li.innerHTML = contents; + + // Add new item to list + document.querySelector('#channelList').append(li); + + // Clear input field + document.querySelector('#channel').value = ''; }); - // When a new vote is announced, add to the unordered list - socket.on('vote totals', data => { - document.querySelector('#yes').innerHTML = data.yes; - document.querySelector('#no').innerHTML = data.no; - document.querySelector('#maybe').innerHTML = data.maybe; + // When a new channel is announced, add to channel list + socket.on('new channel', data => { + add_channel(data["channel"], 0); + }); + + // When a new user is announced, add to global userList + socket.on('new user', data => { + + // remove old list + var myList = document.getElementById('users'); + users.innerHTML = ''; + + // update users with current list - duplicates are handled on the server + for (let key in data) { + var user = [] + + // we have a user in the dict to process + if (data.hasOwnProperty(key)) { + + // build a boostrap formated user list + let li = document.createElement('li'); + li.setAttribute('class',"list-group-item list-group-item-action d-flex justify-content-between align-items-center disabled"); + li.innerHTML = (data[key] + ""+key+""); + document.querySelector('#users').append(li); + console.log(key, data[key]); + } + } }); + + // Load current username +// document.addEventListener('DOMContentLoaded', () => { +// document.querySelector('#user').innerHTML = "Flask: " + +// +// localStorage.getItem('username'); + }); -*/ \ No newline at end of file + + diff --git a/static/addChannel.png b/static/addChannel.png deleted file mode 100644 index dcdcf08cae1917498af1457f4a9abb5053b5887d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9720 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 z z>veyl$Og1d;mT>0i5D9jhFA8wzLS2t4Sy=|7J3W4h2BDMp|{Xm=>H=$@#6u1HN(G( zi;D00(qQ zO+^Re0~8J~H2vwAMgRZl@^+yjgSx#EG$4YK@%_v2}D^i!Y;5oHvgFGIPA_W zOKd#JO?Kzrd(N5j{LjFD%1&0E_d-AzCvcAYzG<)CB6X< zfLp*2Uq- z@ra#46-ej*q%34fre|%dRcE%uOB+sn&rX<@l%l4dQUknsDwGxm9+#gRfTIE7h94wx zTyWTubtcRha>vLt&@U@RfYU1Nxq6h>Z?B%$sQ9UrjDE@d!=EOtE1=teU0M|~>(4BL zri=`m+ThF%;EF610^SN|&G<2EmkXfv3eV&V&}x8d20)tw&IJjF2ynxIunFL{`c6r} zm}%DCgm^g+c6&Y`zt6zJDS@ktz&;-!f4|NS1p)bf#-K~USz`=ZQf3UROiUVMP&IJS z7=s#(sdm$2kmPx#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D1Hwr}K~#8N?V3lc z6hRb5p8>PDQ4|q#T8RiIFrc7xsih_v0L0pLWADFs973j2d-X{+s`aTd`iYqpr1OUBjqZ ziZ)>RFO|>GL-6G-#wgL-zmGQ9Q`ji}bGVC9q6EeU`W^Ea!qlhuj&UMJhcY}Hqx-iy(332l%X*79Nn+OjWTbof+vEarvEvSsUD(eV*&kbN;PRF*AU_lk~hXoGC# z1JJ#q;|Tsju2-+a?NP;qaGISWDV+PtFmAq(T(BidLfyR&K+8We585R$;WL72HG{u%@({)z!;R^wZ(% zsCz_>R(IZ`4P2@t)5NADM&nuZ*Q?AiSPB-PW`n*G>de$HXowt-*^-!kYpAQVB&M?F zVX4qV_<+7L^{O)FV=2*a6?&t!s%xiV>F9^r<;klBs4SIP3g+TV3{|EPRpuOw79}T# z@E3+EppNW3Zb3Ec!Ppaf;6R*;>rtbH_6tL0sO*CnT_V&4k7Fok&D^vy9BRTt+x7Iq z4fqs8WgbJ_GYXWLgf=oV7otbk=%IXSSJ|RZaP*e_4AZK~RunBk9aJd5Ozr3l!3<51 zuAo2fD%wP6Gx~G9Enghf+x?9;sAukPsokRPxDNf&ne_{*HE03E_XFA$^6QSecc_IG zLLYpEHlRm10FRnunf}~reszEAVQ5;cmgGkmm8)0^M?Jm`L~m~b3UyEy(f)f#HG3KQ zH|s{sn2bKTI)H^T2>l}HF0`m6ggytEHFb4-QonU9bgudf-`VNgx92Dp4W)WbtI1A?+0?hp@2}@;}U!%G#Trz*gZGPO7z- z-0)f7T5J`{D{L%z?nqbUHrks`!B(M3m5t>VHXWbP^v71Aq1MLo0-KJ{(z;=*&~RvD nQEZ7sB9TZW5{X2Iw6*;O{QOF - - - - - - - - - - - - - Flack - - - - -
-
- - - - - -
Channels
-
-
    -
    -
  • # channel 1
  • -
  • # channel 2
  • -
-
Flack
-
-
    -
  • message 1
  • -
  • message 2
  • -
  • -
  • -
  • -
  • -
  • -
  • -
  • -
  • -
-
-
- -
-
- + + + + + + + + + + + + + + + Flack + + + +
+ + +
+
+

Flack

+
+
+
+ + +
+
+
+

Users

+
+ + +
+
    + +
+
+
+

+
+
+
+

Channels

+ +
+
+
    +
  • + # General +
  • +
  • + # Classical Music +
  • +
  • + # Theology +
  • +
+
+
+
+

Messages

+
+
+
+
A Basic Panel
+
+
+
+
+
+ + +
+
+
+
+
+
+
+ + + +
+
+
+
+
+
+
+
+ \ No newline at end of file From faea99efe3e59caf3a87acb003f28e66ca110dde Mon Sep 17 00:00:00 2001 From: "A. Hoyt" Date: Thu, 21 Mar 2019 22:50:00 -0400 Subject: [PATCH 04/24] Rebaselining to capture progress and work arounds --- README.md | 9 +++-- application.py | 12 +++++-- static/Index.js | 83 ++++++++++++++++++++++++++++++++++---------- static/style.css | 53 +++++++++++++++++++++++++++- templates/index.html | 54 +++++++++++++++++++++++++--- 5 files changed, 181 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index a1347f3..e3d97e9 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,10 @@ Web Programming with Python and JavaScript -1) User must not block pop-ups from their browser - the application uses prompts to query for a username and stores the value locally -2) The user name is displayed at the top of the Flack screen -3) To add channels select the plus (+) icon next to "Channels" +1) App uses pop-ups to prompt user for username and channels so browser must not block pop-ups for proper functionality + +2) To add channels select the plus (+) icon next to "Channels" + +3) New users joining the app are displayed in the Users column + \ No newline at end of file diff --git a/application.py b/application.py index 9fde1ef..76d9c5d 100644 --- a/application.py +++ b/application.py @@ -26,6 +26,7 @@ def index(): return render_template("index.html") +# set up a user who is connecting to the server @socketio.on('user connect') def connect(data): @@ -36,13 +37,20 @@ def connect(data): if not users: users.update({0: data["username"]}) else: - # determine next dict key and increment + # determine next dict key and increment to add new dictKeys = list(users.keys()) nextKey = max(dictKeys)+1 users.update({nextKey: data["username"]}) - emit("new user", users, broadcast=True) + # let everyone now the user has joined print(users) + emit("add user", users, broadcast=True) + +@socketio.on('post message') +def addMessage(data): + print(data["username"], data["channel"], data["datetime"], data["message"]) + emit("add message", data, broadcast=True) + # check if already registered - avoid duplicates # data = {0: 'sandeep', 1: 'glasknicoff', 2: 'mordor'} diff --git a/static/Index.js b/static/Index.js index 6dcf36e..3418556 100644 --- a/static/Index.js +++ b/static/Index.js @@ -6,16 +6,48 @@ var username; var userList = []; var channelList = []; -loadUsername(); + +// prompt user via popup to enter a new channel +function getChannel() { + newChannel = prompt("Enter a new channel to add...", ""); + return channel; +} + +function postMessage() { + console.log("Post message onlick activated...") + const message = document.querySelector('#message').value; + // need to handel null value in case user enters nothing + socket.emit("post message", { + "user": username, + "channel": "General", + "datetime": Date(), + "message": message + }); +} + +// this needs to be written +function updateChannels() { + + // have we stored a username before + if (!localStorage.getItem('username')) { + username = getUsername(); + localStorage.setItem('username', username ); + socket.emit('user connect', {'username': username}); + } else { + username = localStorage.getItem('username'); + socket.emit('user connect', {'username': username}); + } + +} // prompt user via popup to enter a username before using Flack function getUsername() { // can't give an empty response - keep prompting until not empty while (!username) { - username = prompt("Enter a username for Flack: ", ""); + username = prompt("Enter a display name for Flack: ", ""); if (!username) { - alert("Username not found - you must enter a username to use this site!"); + alert("Username not found - you must enter a display name to use this site!"); } else { return username; } @@ -38,9 +70,26 @@ function loadUsername() { document.addEventListener('DOMContentLoaded', () => { - // when connectedl, start the heavy lifting + // when connected socket.on('connect', () => { + // load user (display) name from local storage or prommpt for input + loadUsername(); + + + + document.getElementById("messagePost").onclick = () => { + console.log("Post onlick activated...") + const message = document.querySelector('#channel').value; + // need to handel null value in case user enters nothing + socket.emit("post message", { + "user": username, + "channel": "General", + "datetime": Date(), + "message": message + }); + }; + //document.getElementById("message").addEventListener("click", () => { // const selection = button.dataset.message; //get like document.querySelector('#channel').value; // socket.emit('send-message', {'selection': "CHANNEL"}); // send-message w/ dict multiple elements @@ -57,8 +106,8 @@ document.addEventListener('DOMContentLoaded', () => { }); - // Add channel to the unordered channel list - used for testing - socket.on('channel list', data => { + // Add channel to channel + socket.on('add channel', data => { console.log("Processing server response..."); const contents = `${data.channel}`; @@ -79,16 +128,19 @@ document.addEventListener('DOMContentLoaded', () => { add_channel(data["channel"], 0); }); + socket.on('add message', data => { + console.log("Got to add message", data) + }); + // When a new user is announced, add to global userList - socket.on('new user', data => { + socket.on('add user', data => { - // remove old list + // remove any old lists var myList = document.getElementById('users'); users.innerHTML = ''; // update users with current list - duplicates are handled on the server for (let key in data) { - var user = [] // we have a user in the dict to process if (data.hasOwnProperty(key)) { @@ -98,16 +150,9 @@ document.addEventListener('DOMContentLoaded', () => { li.setAttribute('class',"list-group-item list-group-item-action d-flex justify-content-between align-items-center disabled"); li.innerHTML = (data[key] + ""+key+""); document.querySelector('#users').append(li); - console.log(key, data[key]); - } - } - }); - - // Load current username -// document.addEventListener('DOMContentLoaded', () => { -// document.querySelector('#user').innerHTML = "Flask: " + -// -// localStorage.getItem('username'); + } // if + } // for + }); //socket.on add user }); diff --git a/static/style.css b/static/style.css index d1637c2..2d8d99a 100644 --- a/static/style.css +++ b/static/style.css @@ -1,6 +1,57 @@ -/* deleted ass css configs except body color */ +/* Flack css configs */ body { background-color: #f2f2f2; +} + +.btn { + background-color: #f2f2f2; +} + +.btn:focus,.btn:active { + outline: none; + box-shadow: none; +} + +.message:focus,.message:active { + outline: none; + box-shadow: none; +} + +.time_date { + color: #747474; + display: block; + font-size: 14px; + margin: 8px 0 0; +} + + .message_text p { + background: #ebebeb none repeat scroll 0 0; + border-radius: 3px; + color: #646464; + font-size: 14px; + margin: 0; + padding: 5px 10px 5px 10px; + width: 100%; +} + +.message_img { + display: inline-block; + width: 6%; +} +.message_content { + display: inline-block; + padding: 5 5 25 10px; + vertical-align: top; + width: 92%; + } + +.mesgs { + float: left; + padding: 30px 15px 20px 25px; + width: 95%; +} + + diff --git a/templates/index.html b/templates/index.html index 5800f98..dd06d97 100644 --- a/templates/index.html +++ b/templates/index.html @@ -47,7 +47,9 @@


Channels

- + + +
    @@ -63,12 +65,54 @@

    Channels

+ +

Messages

-
-
A Basic Panel
+
+
+ + +
+
+ +
+
+ Mike | 11:01 AM | June 9 +
+

Test which is a new approach to have all + solutions

+
+
+
+
+ sunil +
+
+ Larry | 11:01 AM | Yesterday +
+

Test, which is a new approach to have

+
+
+ +
+
+ sunil +
+
+ Tony | 11:01 AM | Today +
+

We work directly with our designers and suppliers, + and sell direct to you, which means quality, exclusive + products, at a price anyone can afford.

+
+
+
+
+ +
@@ -83,9 +127,9 @@

Messages

- + - +
From 9be05eeaa6aa1640dfa17b8e58c249c74cbb9355 Mon Sep 17 00:00:00 2001 From: "A. Hoyt" Date: Thu, 21 Mar 2019 23:17:32 -0400 Subject: [PATCH 05/24] Basic messaging now works --- static/Index.js | 28 ++++++++-------------------- templates/index.html | 4 ++-- 2 files changed, 10 insertions(+), 22 deletions(-) diff --git a/static/Index.js b/static/Index.js index 3418556..5e871ca 100644 --- a/static/Index.js +++ b/static/Index.js @@ -13,19 +13,7 @@ function getChannel() { return channel; } -function postMessage() { - console.log("Post message onlick activated...") - const message = document.querySelector('#message').value; - // need to handel null value in case user enters nothing - socket.emit("post message", { - "user": username, - "channel": "General", - "datetime": Date(), - "message": message - }); -} - -// this needs to be written +// this still needs to be written function updateChannels() { // have we stored a username before @@ -80,14 +68,14 @@ document.addEventListener('DOMContentLoaded', () => { document.getElementById("messagePost").onclick = () => { console.log("Post onlick activated...") - const message = document.querySelector('#channel').value; + const message = document.querySelector('#message').value; // need to handel null value in case user enters nothing - socket.emit("post message", { - "user": username, - "channel": "General", - "datetime": Date(), - "message": message - }); + datetime = Date(); + socket.emit('post message', {'username': username, 'channel': "General", + 'datetime': datetime, 'message': message} + ); + document.querySelector('#message').value = ''; + console.log("emit completed...") }; //document.getElementById("message").addEventListener("click", () => { diff --git a/templates/index.html b/templates/index.html index dd06d97..e418aa9 100644 --- a/templates/index.html +++ b/templates/index.html @@ -127,9 +127,9 @@

Messages

- + - +
From 88e73ff4d7c1954b492b1491cd9079c5c8044ec2 Mon Sep 17 00:00:00 2001 From: "A. Hoyt" Date: Fri, 22 Mar 2019 14:25:45 -0400 Subject: [PATCH 06/24] Saving snapshot before making substantial changes --- application.py | 15 ++++++- static/Index.js | 73 ++++++++++++++++++++++++++++--- static/style.css | 5 --- templates/index.html | 101 +++++++++++++++++++++++++------------------ 4 files changed, 139 insertions(+), 55 deletions(-) diff --git a/application.py b/application.py index 76d9c5d..7fc4fd4 100644 --- a/application.py +++ b/application.py @@ -16,7 +16,7 @@ # Global lists and dicts channels = [] -messages = {} +messages = [] users = {} MESSAGELIMIT = 100 @@ -30,6 +30,8 @@ def index(): @socketio.on('user connect') def connect(data): + #need to add loading list of existing channels + # check if user already connected if (data["username"] not in users.values()): @@ -49,8 +51,19 @@ def connect(data): @socketio.on('post message') def addMessage(data): print(data["username"], data["channel"], data["datetime"], data["message"]) + messages.append(data) + print(messages) emit("add message", data, broadcast=True) +""" + iterate over a list of dicts +dataList = [{'a': 1}, {'b': 3}, {'c': 5}] +for dic in dataList: + for key in dic: + print(dic[key]) +""" + + # check if already registered - avoid duplicates # data = {0: 'sandeep', 1: 'glasknicoff', 2: 'mordor'} diff --git a/static/Index.js b/static/Index.js index 5e871ca..9e1e626 100644 --- a/static/Index.js +++ b/static/Index.js @@ -6,6 +6,7 @@ var username; var userList = []; var channelList = []; +var months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]; // prompt user via popup to enter a new channel function getChannel() { @@ -13,7 +14,7 @@ function getChannel() { return channel; } -// this still needs to be written +// this still needs to be re-written function updateChannels() { // have we stored a username before @@ -61,14 +62,16 @@ document.addEventListener('DOMContentLoaded', () => { // when connected socket.on('connect', () => { - // load user (display) name from local storage or prommpt for input + // load the users (display) name from local storage or prompt for one loadUsername(); + // load previous channel that user was in - + // user is posting a new message document.getElementById("messagePost").onclick = () => { console.log("Post onlick activated...") const message = document.querySelector('#message').value; + // need to handel null value in case user enters nothing datetime = Date(); socket.emit('post message', {'username': username, 'channel': "General", @@ -94,7 +97,7 @@ document.addEventListener('DOMContentLoaded', () => { }); - // Add channel to channel + // OLD - REMOVE Add Channel - change "new channel" to this - adds a channel to channel list socket.on('add channel', data => { console.log("Processing server response..."); @@ -116,11 +119,67 @@ document.addEventListener('DOMContentLoaded', () => { add_channel(data["channel"], 0); }); + //************************************************ + // Add Message - add a new message coming in and add to display list + socket.on('add message', data => { - console.log("Got to add message", data) + console.log("Adding message...", data) + + // build the datetime for the posted message + let d = new Date(); + let year = d.getFullYear(); + let month = months[d.getMonth()]; + let day = d.getDate(); + let hours = d.getHours(); + let minutes = d.getMinutes(); + + // make human readable 12 hour format + let ampm = hours >= 12 ? 'PM' : 'AM'; + hours = hours % 12; + hours = hours ? hours : 12; // '0' hour is '12' + minutes = minutes < 10 ? '0' + minutes : minutes; + let time = hours + ':' + minutes + ' ' + ampm; + + // build the bootstrap formatted user message + let msgHeader = "
"; + + let msgIdentifier = data["username"]+" | "+time+" | "+month+" "+day+", "+year; + + let msgSeperator = "

"; + + let msgTrailer = "


"; + + let msg = msgHeader + msgIdentifier + msgSeperator + data["message"] + msgTrailer + + let li = document.createElement('li'); + li.setAttribute('class',"list-group-item"); + + li.innerHTML = msg; + document.querySelector('#messages').append(li); + + + }); - // When a new user is announced, add to global userList + // data["username"] + // data["channel"] + // data["datetime"] + // data["message"]) +// let li = document.createElement('li'); +// li.setAttribute('class',"list-group-item list-group-item-action d-flex justify-content-between align-items-center disabled"); +// li.innerHTML = (data[key] + ""+key+""); +// document.querySelector('#users').append(li); + + + + + + + + + + // Add User - when a new user is announced, add to global userList socket.on('add user', data => { // remove any old lists @@ -133,7 +192,7 @@ document.addEventListener('DOMContentLoaded', () => { // we have a user in the dict to process if (data.hasOwnProperty(key)) { - // build a boostrap formated user list + // build a bootstrap formatted user list let li = document.createElement('li'); li.setAttribute('class',"list-group-item list-group-item-action d-flex justify-content-between align-items-center disabled"); li.innerHTML = (data[key] + ""+key+""); diff --git a/static/style.css b/static/style.css index 2d8d99a..ddbe04a 100644 --- a/static/style.css +++ b/static/style.css @@ -46,11 +46,6 @@ body { width: 92%; } -.mesgs { - float: left; - padding: 30px 15px 20px 25px; - width: 95%; -} diff --git a/templates/index.html b/templates/index.html index e418aa9..144e7fa 100644 --- a/templates/index.html +++ b/templates/index.html @@ -39,6 +39,8 @@

Users

    + +
@@ -48,18 +50,27 @@

Channels

- - +
+ +
-
    -
  • + +
      + + +
    • # General
    • -
    • +
    • # Classical Music
    • -
    • +
    • # Theology
    @@ -72,45 +83,51 @@

    Messages

    -
    - - -
    -
    - -
    -
    - Mike | 11:01 AM | June 9 -
    -

    Test which is a new approach to have all - solutions

    +
    + + +
      +
    • +
      +
      -
    -
    -
    - sunil -
    -
    - Larry | 11:01 AM | Yesterday -
    -

    Test, which is a new approach to have

    +
    + Mike | 11:01 AM | June 9 +
    +

    Test which is a new approach to have all + solutions

    +
    -
    - -
    -
    - sunil -
    -
    - Tony | 11:01 AM | Today -
    -

    We work directly with our designers and suppliers, - and sell direct to you, which means quality, exclusive - products, at a price anyone can afford.

    + +
  • +
  • +
    + sunil +
    +
    + Larry | 11:01 AM | Yesterday +
    +

    Test, which is a new approach to have

    +
    +
    +
  • + +
  • +
    + sunil
    -
-
-
+
+ Tony | 11:01 AM | Today +
+

We work directly with our designers and suppliers, + and sell direct to you, which means quality, exclusive + products, at a price anyone can afford.

+
+
+ + + +
From 38f1f00f409325076a18a1700280d340f1d29462 Mon Sep 17 00:00:00 2001 From: "A. Hoyt" Date: Sat, 23 Mar 2019 11:23:55 -0400 Subject: [PATCH 07/24] fixed messaging and loadUsername() issues --- application.py | 18 +++++++++++++++--- static/Index.js | 43 ++++++++++++++++++++----------------------- 2 files changed, 35 insertions(+), 26 deletions(-) diff --git a/application.py b/application.py index 7fc4fd4..0308cf3 100644 --- a/application.py +++ b/application.py @@ -15,7 +15,8 @@ # Session(app) # Global lists and dicts -channels = [] +channels = {} +message = {} messages = [] users = {} @@ -29,8 +30,17 @@ def index(): # set up a user who is connecting to the server @socketio.on('user connect') def connect(data): - - #need to add loading list of existing channels + global channels + messages = [] + + # check if channels empty - first time through + if not channels: + messages.insert(0, "Welcome to Flack!") + channels['General'] = messages + emit("add channel", channels, broadcast=True) + else: + # already have some channels so communicate + emit("add channel", channels, broadcast=True) # check if user already connected if (data["username"] not in users.values()): @@ -48,6 +58,8 @@ def connect(data): print(users) emit("add user", users, broadcast=True) + + @socketio.on('post message') def addMessage(data): print(data["username"], data["channel"], data["datetime"], data["message"]) diff --git a/static/Index.js b/static/Index.js index 9e1e626..94bf0ed 100644 --- a/static/Index.js +++ b/static/Index.js @@ -31,7 +31,7 @@ function updateChannels() { // prompt user via popup to enter a username before using Flack function getUsername() { - + console.log("getUsername"); // can't give an empty response - keep prompting until not empty while (!username) { username = prompt("Enter a display name for Flack: ", ""); @@ -45,7 +45,7 @@ function getUsername() { // check if username stored locally - if not there, we prompt for one function loadUsername() { - + console.log("loadUsername"); // have we stored a username before if (!localStorage.getItem('username')) { username = getUsername(); @@ -96,7 +96,7 @@ document.addEventListener('DOMContentLoaded', () => { // }; }); - +/* // OLD - REMOVE Add Channel - change "new channel" to this - adds a channel to channel list socket.on('add channel', data => { @@ -115,15 +115,29 @@ document.addEventListener('DOMContentLoaded', () => { }); // When a new channel is announced, add to channel list - socket.on('new channel', data => { - add_channel(data["channel"], 0); + socket.on('add channel', data => { + console.log("Adding channel...", data); + + // remove any old lists + var myList = document.getElementById('channels'); + .innerHTML = ''; + +
  • + # General +
  • + + + + //add_channel(data["channel"], 0); }); +*/ //************************************************ // Add Message - add a new message coming in and add to display list socket.on('add message', data => { - console.log("Adding message...", data) + console.log("Adding message...", data); // build the datetime for the posted message let d = new Date(); @@ -162,23 +176,6 @@ document.addEventListener('DOMContentLoaded', () => { }); - // data["username"] - // data["channel"] - // data["datetime"] - // data["message"]) -// let li = document.createElement('li'); -// li.setAttribute('class',"list-group-item list-group-item-action d-flex justify-content-between align-items-center disabled"); -// li.innerHTML = (data[key] + ""+key+""); -// document.querySelector('#users').append(li); - - - - - - - - - // Add User - when a new user is announced, add to global userList socket.on('add user', data => { From a4cb7cff01368eb4d46ec6771ca96d15f7b6a6e0 Mon Sep 17 00:00:00 2001 From: "A. Hoyt" Date: Sat, 23 Mar 2019 12:33:31 -0400 Subject: [PATCH 08/24] Changes to channel selection --- application.py | 10 +++++++++- static/Index.js | 27 ++++++++++++++++----------- templates/index.html | 28 +++++++++++++++------------- 3 files changed, 40 insertions(+), 25 deletions(-) diff --git a/application.py b/application.py index 0308cf3..0a9d90e 100644 --- a/application.py +++ b/application.py @@ -49,7 +49,7 @@ def connect(data): if not users: users.update({0: data["username"]}) else: - # determine next dict key and increment to add new + # determine next dict key and increment to add new user dictKeys = list(users.keys()) nextKey = max(dictKeys)+1 users.update({nextKey: data["username"]}) @@ -59,6 +59,14 @@ def connect(data): emit("add user", users, broadcast=True) +@socketio.on('get channel') +def addMessage(data): + # build a dict of requested messages and send + # emit to select channel + print("Request for channel: "+data['channel']) + + + @socketio.on('post message') def addMessage(data): diff --git a/static/Index.js b/static/Index.js index 94bf0ed..85af11c 100644 --- a/static/Index.js +++ b/static/Index.js @@ -9,11 +9,21 @@ var channelList = []; var months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]; // prompt user via popup to enter a new channel -function getChannel() { - newChannel = prompt("Enter a new channel to add...", ""); - return channel; +function getChannel(channelName) { + console.log("getChannel "+channelName) + + // source of truth is on the server - make a request + socket.emit('get channel', {'channel': channelName}); } + +// select + to add channel +//function addChannel(channelName) { +// console.log("getChannel "+channelName) + // newChannel = prompt("Enter a new channel to add...", ""); +// return channel; +//} + // this still needs to be re-written function updateChannels() { @@ -133,9 +143,7 @@ document.addEventListener('DOMContentLoaded', () => { }); */ - //************************************************ // Add Message - add a new message coming in and add to display list - socket.on('add message', data => { console.log("Adding message...", data); @@ -171,9 +179,6 @@ document.addEventListener('DOMContentLoaded', () => { li.innerHTML = msg; document.querySelector('#messages').append(li); - - - }); // Add User - when a new user is announced, add to global userList @@ -194,9 +199,9 @@ document.addEventListener('DOMContentLoaded', () => { li.setAttribute('class',"list-group-item list-group-item-action d-flex justify-content-between align-items-center disabled"); li.innerHTML = (data[key] + ""+key+""); document.querySelector('#users').append(li); - } // if - } // for - }); //socket.on add user + } // end if + } // end for + }); // end socket.on add user }); diff --git a/templates/index.html b/templates/index.html index 144e7fa..700298e 100644 --- a/templates/index.html +++ b/templates/index.html @@ -61,19 +61,21 @@

    Channels

    class="list-group list-group-item-secondary d-flex list-group-item-action active"> -
  • - # General -
  • -
  • - # Classical Music -
  • -
  • - # Theology -
  • - + + + + + + +
    From 7ccd19ea7c351c28a1620546a9ce06e7fc1d2405 Mon Sep 17 00:00:00 2001 From: "A. Hoyt" Date: Sat, 23 Mar 2019 16:27:19 -0400 Subject: [PATCH 09/24] tracking channel state and restoring if user rejoins --- application.py | 46 ++++++++++++++----- requirements.txt | 1 + static/Index.js | 106 ++++++++++++++++++++++++++++++++----------- templates/index.html | 10 ++-- 4 files changed, 119 insertions(+), 44 deletions(-) diff --git a/application.py b/application.py index 0a9d90e..480635a 100644 --- a/application.py +++ b/application.py @@ -1,5 +1,6 @@ import os - +import datetime +import json from flask import Flask, render_template, redirect, request, jsonify, request, flash, url_for, session from flask_socketio import SocketIO, emit @@ -12,7 +13,6 @@ socketio = SocketIO(app) app.secret_key = os.urandom(32) -# Session(app) # Global lists and dicts channels = {} @@ -33,9 +33,17 @@ def connect(data): global channels messages = [] + # get server date / time + current = datetime.datetime.now() + # check if channels empty - first time through if not channels: - messages.insert(0, "Welcome to Flack!") + + # always provide a general channel just like slack + messages.insert(0, {'username': "System", + 'channel': "General", + 'datetime': current.__str__(), # use dunder method to convert to json + 'message': "Welcome to Flack!"}) channels['General'] = messages emit("add channel", channels, broadcast=True) else: @@ -60,16 +68,36 @@ def connect(data): @socketio.on('get channel') -def addMessage(data): - # build a dict of requested messages and send - # emit to select channel +def getChannel(data): + global channels + + # extract requested dict messages and send + list = channels.get(data['channel'],) + selectedChannel = {"channel": data['channel'], "messages": list} + + # dump debug data + print(list) + print(data['channel']) + print("Current channels: ", channels) print("Request for channel: "+data['channel']) + # emit to "select channel" + emit("select channel", selectedChannel, broadcast=True) + + +@socketio.on('new-channel') +def addChannel(data): + channel = data["selection"] + print("new-channel for: "+ channel) + results = {"success": True, "channel": channel} + emit("announce channel", results, broadcast=True) @socketio.on('post message') def addMessage(data): + # add message to list + print(data["username"], data["channel"], data["datetime"], data["message"]) messages.append(data) print(messages) @@ -93,12 +121,6 @@ def addMessage(data): -@socketio.on('new-channel') -def addChannel(data): - channel = data["selection"] - print("new-channel for: "+ channel) - results = {"success": True, "channel": channel} - emit("announce channel", results, broadcast=True) @socketio.on('debug') def debug(data): diff --git a/requirements.txt b/requirements.txt index 55ef84d..260d497 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,3 @@ Flask Flask-SocketIO +datetime \ No newline at end of file diff --git a/static/Index.js b/static/Index.js index 85af11c..a5976d6 100644 --- a/static/Index.js +++ b/static/Index.js @@ -3,21 +3,38 @@ var socket = io.connect(location.protocol + '//' + document.domain + ':' + locat // globals var username; +var activeChannel; var userList = []; var channelList = []; var months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]; // prompt user via popup to enter a new channel -function getChannel(channelName) { - console.log("getChannel "+channelName) +function selectChannel(channelName) { + console.log("getChannel "+channelName); - // source of truth is on the server - make a request + // make sure messages are going to the right channel + activeChannel = channelName; + + // source of truth is on the server - request message for the selected channel socket.emit('get channel', {'channel': channelName}); } +// load prior channel state - part of project requirements +function loadChannel() { -// select + to add channel + // does user have a prior active channel - must logout cleanly for this to work correctly + if (!localStorage.getItem('channel')) { + localStorage.setItem('channel', "General"); + activeChannel = "General" + } else { + // otherwise we load previous + activeChannel = localStorage.getItem('channel'); + } +} + + +// select + to add channel goes here //function addChannel(channelName) { // console.log("getChannel "+channelName) // newChannel = prompt("Enter a new channel to add...", ""); @@ -36,7 +53,6 @@ function updateChannels() { username = localStorage.getItem('username'); socket.emit('user connect', {'username': username}); } - } // prompt user via popup to enter a username before using Flack @@ -72,24 +88,26 @@ document.addEventListener('DOMContentLoaded', () => { // when connected socket.on('connect', () => { - // load the users (display) name from local storage or prompt for one - loadUsername(); - - // load previous channel that user was in - - // user is posting a new message - document.getElementById("messagePost").onclick = () => { - console.log("Post onlick activated...") - const message = document.querySelector('#message').value; - - // need to handel null value in case user enters nothing - datetime = Date(); - socket.emit('post message', {'username': username, 'channel': "General", - 'datetime': datetime, 'message': message} - ); - document.querySelector('#message').value = ''; - console.log("emit completed...") - }; + // load the users (display) name from local storage or prompt for one + loadUsername(); + + // load previous channel that user was in or default to general + loadChannel(); + + // user is posting a new message + document.getElementById("messagePost").onclick = () => { + console.log("Post onlick activated..."); + const message = document.querySelector('#message').value; + + // need to handel null value in case user enters nothing + let datetime = Date(); + socket.emit('post message', {'username': username, 'channel': activeChannel, + 'datetime': datetime, 'message': message} + ); + document.querySelector('#message').value = ''; + console.log("emit completed...") + }; + }); //document.getElementById("message").addEventListener("click", () => { // const selection = button.dataset.message; //get like document.querySelector('#channel').value; @@ -105,8 +123,42 @@ document.addEventListener('DOMContentLoaded', () => { // socket.emit('debug', {'message': selection}); // }; - }); -/* + + + socket.on('select channel', data => { + + // debug info + //console.log("DATA FROM SELECT channel: "+data['channel']); + // console.log("DATA FROM SELECT channel: "+data['messages']); + + + // extract channel messages and populate page + let messages = data['messages']; + + + }); + + /* + // this builds the channel list + + // remove previous channel entries + // var messageList = document.getElementById('channels'); + //channels.innerHTML = ''; + for (let i = 0; i < messages.length; i++) { + + // building a bootstrap formatted channel list + let button = document.createElement('button'); + button.setAttribute('class',"list-group-item list-group-item-action"); + button.setAttribute('type', "button"); + button.setAttribute('onclick', "getChannel('General');"); + button.innerHTML = list[i]; + document.querySelector('#channels').append(button); + } // end for + + + + + // OLD - REMOVE Add Channel - change "new channel" to this - adds a channel to channel list socket.on('add channel', data => { @@ -162,7 +214,7 @@ document.addEventListener('DOMContentLoaded', () => { minutes = minutes < 10 ? '0' + minutes : minutes; let time = hours + ':' + minutes + ' ' + ampm; - // build the bootstrap formatted user message + // building a bootstrap formatted user message let msgHeader = "
    "; @@ -185,7 +237,7 @@ document.addEventListener('DOMContentLoaded', () => { socket.on('add user', data => { // remove any old lists - var myList = document.getElementById('users'); + var userList = document.getElementById('users'); users.innerHTML = ''; // update users with current list - duplicates are handled on the server diff --git a/templates/index.html b/templates/index.html index 700298e..1047623 100644 --- a/templates/index.html +++ b/templates/index.html @@ -50,7 +50,7 @@

    Channels

    -
    @@ -61,16 +61,16 @@

    Channels

    class="list-group list-group-item-secondary d-flex list-group-item-action active"> - - - - From e79f893cc236818d6a554adb727419671e1276ce Mon Sep 17 00:00:00 2001 From: "A. Hoyt" Date: Sat, 23 Mar 2019 18:30:57 -0400 Subject: [PATCH 10/24] more updates on channel state handling --- application.py | 12 ++++----- static/Index.js | 59 ++++++++++++++++++++++++++++++++------------ templates/index.html | 4 +-- 3 files changed, 50 insertions(+), 25 deletions(-) diff --git a/application.py b/application.py index 480635a..273d471 100644 --- a/application.py +++ b/application.py @@ -84,14 +84,12 @@ def getChannel(data): # emit to "select channel" emit("select channel", selectedChannel, broadcast=True) - - -@socketio.on('new-channel') +@socketio.on('new channel') def addChannel(data): - channel = data["selection"] - print("new-channel for: "+ channel) - results = {"success": True, "channel": channel} - emit("announce channel", results, broadcast=True) + # channel = data["selection"] + print("new-channel for: "+ data['channel']) + # results = {"success": True, "channel": channel} + # emit("announce channel", results, broadcast=True) @socketio.on('post message') diff --git a/static/Index.js b/static/Index.js index a5976d6..b66c483 100644 --- a/static/Index.js +++ b/static/Index.js @@ -7,17 +7,18 @@ var activeChannel; var userList = []; var channelList = []; -var months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]; +var months = ["January", "February", "March", "April", "May", "June", "July", + "August", "September", "October", "November", "December"]; // prompt user via popup to enter a new channel function selectChannel(channelName) { - console.log("getChannel "+channelName); + console.log("getChannel " + channelName); - // make sure messages are going to the right channel - activeChannel = channelName; + // make sure messages are going to the right channel + activeChannel = channelName; - // source of truth is on the server - request message for the selected channel - socket.emit('get channel', {'channel': channelName}); + // source of truth is on the server - request message for the selected channel + socket.emit('get channel', {'channel': channelName}); } // load prior channel state - part of project requirements @@ -25,21 +26,47 @@ function loadChannel() { // does user have a prior active channel - must logout cleanly for this to work correctly if (!localStorage.getItem('channel')) { - localStorage.setItem('channel', "General"); - activeChannel = "General" + localStorage.setItem('channel', "General"); + activeChannel = "General" } else { // otherwise we load previous - activeChannel = localStorage.getItem('channel'); + activeChannel = localStorage.getItem('channel'); } } +// builds the channel list +function buildChannelList(activeChannel) { -// select + to add channel goes here -//function addChannel(channelName) { -// console.log("getChannel "+channelName) - // newChannel = prompt("Enter a new channel to add...", ""); -// return channel; -//} + // loop through channel list - set active channel + + // building a bootstrap formatted channel list + let button = document.createElement('button'); + button.setAttribute('class', "list-group-item list-group-item-action"); + button.setAttribute('type', "button"); + button.setAttribute('onclick', "getChannel('General');"); + button.innerHTML = list[i]; + document.querySelector('#channels').append(button); +} + + +// add channel from prompt +function addChannel() { + + let channel = prompt("Enter a new channel to add...", ""); + if (channel === null) { + return; // user canceled - break out of the function + } + // checking for duplicate channels + if (channelList.indexOf(channel) > -1) { + alert("Duplicate channel name - please try again!") + + } else { + // not in the array - add channel and make it the active one + activeChannel = channel; + channelList.push(channel); + socket.emit('new channel', {'channel': channel}); + } +} // this still needs to be re-written function updateChannels() { @@ -60,7 +87,7 @@ function getUsername() { console.log("getUsername"); // can't give an empty response - keep prompting until not empty while (!username) { - username = prompt("Enter a display name for Flack: ", ""); + let username = prompt("Enter a display name for Flack: ", ""); if (!username) { alert("Username not found - you must enter a display name to use this site!"); } else { diff --git a/templates/index.html b/templates/index.html index 1047623..b1bef59 100644 --- a/templates/index.html +++ b/templates/index.html @@ -50,7 +50,7 @@

    Channels

    -
    @@ -60,7 +60,7 @@

    Channels

      - + From 0e7b0e3d3e0fde9d792851319f39699e2a28ac1d Mon Sep 17 00:00:00 2001 From: "A. Hoyt" Date: Sun, 24 Mar 2019 00:21:12 -0400 Subject: [PATCH 11/24] Added personal touch bage that tracks number of user messages posted --- application.py | 12 ++++++--- static/Index.js | 63 ++++++++++++++++++++++++++++---------------- static/style.css | 6 +++++ templates/index.html | 55 ++------------------------------------ 4 files changed, 56 insertions(+), 80 deletions(-) diff --git a/application.py b/application.py index 273d471..9634f51 100644 --- a/application.py +++ b/application.py @@ -1,6 +1,5 @@ import os import datetime -import json from flask import Flask, render_template, redirect, request, jsonify, request, flash, url_for, session from flask_socketio import SocketIO, emit @@ -86,11 +85,16 @@ def getChannel(data): @socketio.on('new channel') def addChannel(data): - # channel = data["selection"] + global channels + + # add the new channel to the channel list + channels.update({"channel": data['channel'],"messages": []}) + selectedChannel = {"channel": data['channel'], "messages": []} + print("new-channel for: "+ data['channel']) - # results = {"success": True, "channel": channel} - # emit("announce channel", results, broadcast=True) + # let everyone know a new channel is available - emit to "select channel" + emit("select channel", selectedChannel, broadcast=True) @socketio.on('post message') def addMessage(data): diff --git a/static/Index.js b/static/Index.js index b66c483..cef0dcb 100644 --- a/static/Index.js +++ b/static/Index.js @@ -28,6 +28,7 @@ function loadChannel() { if (!localStorage.getItem('channel')) { localStorage.setItem('channel', "General"); activeChannel = "General" + channelList.push(activeChannel); } else { // otherwise we load previous activeChannel = localStorage.getItem('channel'); @@ -37,15 +38,29 @@ function loadChannel() { // builds the channel list function buildChannelList(activeChannel) { + // clear channels + var userList = document.getElementById('channels'); + channels.innerHTML = ''; + console.log("buildChannelList: ", activeChannel); + console.log("chanelList Length: ", channelList.length); + // loop through channel list - set active channel + for (let i = 0; i < channelList.length; i++) { - // building a bootstrap formatted channel list - let button = document.createElement('button'); - button.setAttribute('class', "list-group-item list-group-item-action"); - button.setAttribute('type', "button"); - button.setAttribute('onclick', "getChannel('General');"); - button.innerHTML = list[i]; - document.querySelector('#channels').append(button); + // building a bootstrap formatted channel list + let button = document.createElement('button'); + if (channelList[i] == activeChannel) { + console.log("Building channel: ", channelList[i]) + button.setAttribute('class', "list-group-item list-group-item-action active"); + } else { + button.setAttribute('class', "list-group-item list-group-item-action"); + } + button.setAttribute('type', "button"); + button.setAttribute('onclick', "selectChannel('"+channelList[i]+"');"); + button.innerHTML = channelList[i]; + console.log("BUTTON: ", button) + document.querySelector('#channels').append(button); + } } @@ -68,18 +83,9 @@ function addChannel() { } } -// this still needs to be re-written -function updateChannels() { - - // have we stored a username before - if (!localStorage.getItem('username')) { - username = getUsername(); - localStorage.setItem('username', username ); - socket.emit('user connect', {'username': username}); - } else { - username = localStorage.getItem('username'); - socket.emit('user connect', {'username': username}); - } +function myFunction() { + var elmnt = document.getElementById("content"); + elmnt.scrollIntoView(); } // prompt user via popup to enter a username before using Flack @@ -99,10 +105,12 @@ function getUsername() { // check if username stored locally - if not there, we prompt for one function loadUsername() { console.log("loadUsername"); + // have we stored a username before if (!localStorage.getItem('username')) { username = getUsername(); localStorage.setItem('username', username ); + localStorage.setItem('message-count', 0 ); socket.emit('user connect', {'username': username}); } else { username = localStorage.getItem('username'); @@ -155,12 +163,12 @@ document.addEventListener('DOMContentLoaded', () => { socket.on('select channel', data => { // debug info - //console.log("DATA FROM SELECT channel: "+data['channel']); + console.log("DATA FROM SELECT channel: "+data['channel']); // console.log("DATA FROM SELECT channel: "+data['messages']); - + buildChannelList(data['channel']); // extract channel messages and populate page - let messages = data['messages']; + //let messages = data['messages']; }); @@ -225,6 +233,7 @@ document.addEventListener('DOMContentLoaded', () => { // Add Message - add a new message coming in and add to display list socket.on('add message', data => { console.log("Adding message...", data); + let messageCount = parseInt(localStorage.getItem('message-count')); // build the datetime for the posted message let d = new Date(); @@ -256,12 +265,18 @@ document.addEventListener('DOMContentLoaded', () => { let li = document.createElement('li'); li.setAttribute('class',"list-group-item"); + li.setAttribute('id',"posted-message-"+messageCount); li.innerHTML = msg; document.querySelector('#messages').append(li); + document.querySelector("#"+data["username"]).innerHTML = messageCount+1; + let element = document.getElementById("posted-message-"+messageCount); + element.scrollIntoView(); + localStorage.setItem('message-count', messageCount+1); }); // Add User - when a new user is announced, add to global userList socket.on('add user', data => { + let messageCount = parseInt(localStorage.getItem('message-count')); // remove any old lists var userList = document.getElementById('users'); @@ -272,11 +287,13 @@ document.addEventListener('DOMContentLoaded', () => { // we have a user in the dict to process if (data.hasOwnProperty(key)) { + console.log("KEY VALUE: ",data[key]) // build a bootstrap formatted user list let li = document.createElement('li'); li.setAttribute('class',"list-group-item list-group-item-action d-flex justify-content-between align-items-center disabled"); - li.innerHTML = (data[key] + ""+key+""); + li.innerHTML = (data[key] + ""+messageCount+""); document.querySelector('#users').append(li); } // end if } // end for diff --git a/static/style.css b/static/style.css index ddbe04a..8c96f70 100644 --- a/static/style.css +++ b/static/style.css @@ -8,6 +8,12 @@ body { background-color: #f2f2f2; } +#messages { +overflow-y: auto; +max-height: calc(95vh - 150px); +} + + .btn:focus,.btn:active { outline: none; box-shadow: none; diff --git a/templates/index.html b/templates/index.html index b1bef59..2f21187 100644 --- a/templates/index.html +++ b/templates/index.html @@ -61,18 +61,6 @@

      Channels

      class="list-group list-group-item-secondary d-flex list-group-item-action active"> - - - -
    @@ -86,51 +74,12 @@

    Messages

    +
      - -
        -
      • -
        - -
        -
        - Mike | 11:01 AM | June 9 -
        -

        Test which is a new approach to have all - solutions

        -
        -
        - -
      • -
      • -
        - sunil -
        -
        - Larry | 11:01 AM | Yesterday -
        -

        Test, which is a new approach to have

        -
        -
        -
      • - -
      • -
        - sunil -
        -
        - Tony | 11:01 AM | Today -
        -

        We work directly with our designers and suppliers, - and sell direct to you, which means quality, exclusive - products, at a price anyone can afford.

        -
        -
        -
      • +
      -
    From 37dc6c5d0f94f8e7b505ae632d2a395ce63a465c Mon Sep 17 00:00:00 2001 From: "A. Hoyt" Date: Sun, 24 Mar 2019 18:52:58 -0400 Subject: [PATCH 12/24] Channel selection properly changes messages - reworked datetime calculations --- application.py | 83 +++++++------------- static/Index.js | 202 +++++++++++++++++++++--------------------------- 2 files changed, 115 insertions(+), 170 deletions(-) diff --git a/application.py b/application.py index 9634f51..2626ca8 100644 --- a/application.py +++ b/application.py @@ -44,10 +44,12 @@ def connect(data): 'datetime': current.__str__(), # use dunder method to convert to json 'message': "Welcome to Flack!"}) channels['General'] = messages - emit("add channel", channels, broadcast=True) + print("Channels after connecting: ", channels) + emit("select channel", channels, broadcast=False) else: # already have some channels so communicate - emit("add channel", channels, broadcast=True) + print(channels) + emit("select channel", channels, broadcast=False) # check if user already connected if (data["username"] not in users.values()): @@ -61,7 +63,7 @@ def connect(data): nextKey = max(dictKeys)+1 users.update({nextKey: data["username"]}) - # let everyone now the user has joined + # let everyone know a user has joined print(users) emit("add user", users, broadcast=True) @@ -70,71 +72,40 @@ def connect(data): def getChannel(data): global channels - # extract requested dict messages and send - list = channels.get(data['channel'],) - selectedChannel = {"channel": data['channel'], "messages": list} - - # dump debug data - print(list) - print(data['channel']) - print("Current channels: ", channels) - print("Request for channel: "+data['channel']) - - # emit to "select channel" - emit("select channel", selectedChannel, broadcast=True) + # emit current channel list + emit("select channel", channels, broadcast=False) @socketio.on('new channel') def addChannel(data): global channels + updatedChannels = [] + # add the new channel to the server channel list + channels.update({data['channel']: []}) - # add the new channel to the channel list - channels.update({"channel": data['channel'],"messages": []}) - selectedChannel = {"channel": data['channel'], "messages": []} + # extract updated list of channels + for key in channels.keys(): + updatedChannels.append(key) - print("new-channel for: "+ data['channel']) + # dump debug data + print("1: ", updatedChannels) - # let everyone know a new channel is available - emit to "select channel" - emit("select channel", selectedChannel, broadcast=True) + # let everyone know a new channel is available + emit("update channels", {'channel': updatedChannels}, broadcast=True) @socketio.on('post message') def addMessage(data): - # add message to list + global channels + + print("2: ", data) + print("3: ", channels) + channels.setdefault(data['channel'], []).append(data) + print("4: ", channels) + + # need to add message to channels array here + #updatedChannels.append(data) + print(data["username"], data["channel"], data["datetime"], data["message"]) messages.append(data) print(messages) emit("add message", data, broadcast=True) - -""" - iterate over a list of dicts -dataList = [{'a': 1}, {'b': 3}, {'c': 5}] -for dic in dataList: - for key in dic: - print(dic[key]) -""" - - - - # check if already registered - avoid duplicates - # data = {0: 'sandeep', 1: 'glasknicoff', 2: 'mordor'} - # print("number: "+data.get(key,0)+1) - # print(data) - # emit("new user", data, broadcast=True) - - - - -@socketio.on('debug') -def debug(data): -# print("debug message: ", data["message"]) - channel = data["message"] - print("debug from server, for: "+ channel) - results = {"success": True, "channel": channel} - emit("announce channel", results, broadcast=True) - -@socketio.on('send-message') -def addChannel(data): - channel = data["selection"] - print("send-message for: "+ channel) - results = {"success": True, "channel": channel} - emit("announce channel", results, broadcast=True) \ No newline at end of file diff --git a/static/Index.js b/static/Index.js index cef0dcb..52c16bc 100644 --- a/static/Index.js +++ b/static/Index.js @@ -4,7 +4,6 @@ var socket = io.connect(location.protocol + '//' + document.domain + ':' + locat // globals var username; var activeChannel; -var userList = []; var channelList = []; var months = ["January", "February", "March", "April", "May", "June", "July", @@ -12,7 +11,7 @@ var months = ["January", "February", "March", "April", "May", "June", "July", // prompt user via popup to enter a new channel function selectChannel(channelName) { - console.log("getChannel " + channelName); + console.log("selectChannel" + channelName); // make sure messages are going to the right channel activeChannel = channelName; @@ -23,11 +22,11 @@ function selectChannel(channelName) { // load prior channel state - part of project requirements function loadChannel() { - + console.log("loadChannel"); // does user have a prior active channel - must logout cleanly for this to work correctly if (!localStorage.getItem('channel')) { localStorage.setItem('channel', "General"); - activeChannel = "General" + activeChannel = "General"; channelList.push(activeChannel); } else { // otherwise we load previous @@ -37,12 +36,10 @@ function loadChannel() { // builds the channel list function buildChannelList(activeChannel) { - + console.log("buildChannel"); // clear channels var userList = document.getElementById('channels'); channels.innerHTML = ''; - console.log("buildChannelList: ", activeChannel); - console.log("chanelList Length: ", channelList.length); // loop through channel list - set active channel for (let i = 0; i < channelList.length; i++) { @@ -50,7 +47,6 @@ function buildChannelList(activeChannel) { // building a bootstrap formatted channel list let button = document.createElement('button'); if (channelList[i] == activeChannel) { - console.log("Building channel: ", channelList[i]) button.setAttribute('class', "list-group-item list-group-item-action active"); } else { button.setAttribute('class', "list-group-item list-group-item-action"); @@ -58,35 +54,62 @@ function buildChannelList(activeChannel) { button.setAttribute('type', "button"); button.setAttribute('onclick', "selectChannel('"+channelList[i]+"');"); button.innerHTML = channelList[i]; - console.log("BUTTON: ", button) + console.log("BUTTON: ", button); document.querySelector('#channels').append(button); } } +// build current message list - user selected another channel +function buildMessageList(messageList) { + console.log("Building message: ", messageList ); + + // clear current message list + var oldMessages = document.getElementById('messages'); + messages.innerHTML = ''; + + //build new message list from server + for (let i = 0; i < messageList.length; i++) { + + // building a bootstrap formatted user message + let msgHeader = "
    "; + + let msgIdentifier = messageList[i]["username"] + messageList[i]["datetime"]; + + let msgSeperator = "

    "; + + let msgTrailer = "


    "; + + let msg = msgHeader + msgIdentifier + msgSeperator + messageList[i]["message"] + msgTrailer; + + let li = document.createElement('li'); + li.setAttribute('class', "list-group-item"); + + li.setAttribute('id', "posted-message-" +i ); + li.innerHTML = msg; + document.querySelector('#messages').append(li); + let element = document.getElementById("posted-message-" + i); + element.scrollIntoView(); + } +} // add channel from prompt function addChannel() { - + console.log("addChannel"); let channel = prompt("Enter a new channel to add...", ""); if (channel === null) { return; // user canceled - break out of the function } // checking for duplicate channels if (channelList.indexOf(channel) > -1) { - alert("Duplicate channel name - please try again!") + alert("Duplicate channel name - please try again!"); } else { - // not in the array - add channel and make it the active one - activeChannel = channel; - channelList.push(channel); + // not in the array - add the channel socket.emit('new channel', {'channel': channel}); } } -function myFunction() { - var elmnt = document.getElementById("content"); - elmnt.scrollIntoView(); -} // prompt user via popup to enter a username before using Flack function getUsername() { @@ -95,7 +118,7 @@ function getUsername() { while (!username) { let username = prompt("Enter a display name for Flack: ", ""); if (!username) { - alert("Username not found - you must enter a display name to use this site!"); + alert("Username not entered - you must enter a display name to use this site!"); } else { return username; } @@ -105,7 +128,6 @@ function getUsername() { // check if username stored locally - if not there, we prompt for one function loadUsername() { console.log("loadUsername"); - // have we stored a username before if (!localStorage.getItem('username')) { username = getUsername(); @@ -134,133 +156,85 @@ document.addEventListener('DOMContentLoaded', () => { console.log("Post onlick activated..."); const message = document.querySelector('#message').value; - // need to handel null value in case user enters nothing - let datetime = Date(); + // build the datetime for the posted message + let d = new Date(); + let year = d.getFullYear(); + let month = months[d.getMonth()]; + let day = d.getDate(); + let hours = d.getHours(); + let minutes = d.getMinutes(); + + // make human readable 12 hour format + let ampm = hours >= 12 ? 'PM' : 'AM'; + hours = hours % 12; + hours = hours ? hours : 12; // '0' hour is '12' + minutes = minutes < 10 ? '0' + minutes : minutes; + let time = hours + ':' + minutes + ' ' + ampm; + let datetime = " | "+time+" | "+month+" "+day+", "+year; + socket.emit('post message', {'username': username, 'channel': activeChannel, - 'datetime': datetime, 'message': message} + 'datetime': datetime, 'message': message} ); document.querySelector('#message').value = ''; - console.log("emit completed...") }; }); - //document.getElementById("message").addEventListener("click", () => { - // const selection = button.dataset.message; //get like document.querySelector('#channel').value; - // socket.emit('send-message', {'selection': "CHANNEL"}); // send-message w/ dict multiple elements - //}); - // Adding a new channel - //document.querySelector('#form').onsubmit = ()=> { - - -// -// const selection = document.querySelector('#channel').value; -// socket.emit('new-channel', {'selection': selection}); // should be create or add-channel: channelName -// socket.emit('debug', {'message': selection}); -// }; - - - socket.on('select channel', data => { - // debug info - console.log("DATA FROM SELECT channel: "+data['channel']); + let messageList = data[activeChannel]; + console.log("MESSAGE LIST: ", messageList); + buildMessageList(messageList); + + /* console.log("SELECT CHANNEL: "+activeChannel ); + for (let i = 0; i < data[activeChannel].length; i++) { + console.log("channel messages", data[activeChannel][i]); + = data[activeChannel][i] + } + console.log("CHANNEL: "+data['channel']); // console.log("DATA FROM SELECT channel: "+data['messages']); - buildChannelList(data['channel']); + // should be channel list + for (let i = 0; i < channelList.length; i++) { + console.log("SELECT CHANNEL"+i+": ", channelList[i]) + } +*/ + buildChannelList(activeChannel); // extract channel messages and populate page //let messages = data['messages']; - - - }); - - /* - // this builds the channel list - - // remove previous channel entries - // var messageList = document.getElementById('channels'); - //channels.innerHTML = ''; - for (let i = 0; i < messages.length; i++) { - - // building a bootstrap formatted channel list - let button = document.createElement('button'); - button.setAttribute('class',"list-group-item list-group-item-action"); - button.setAttribute('type', "button"); - button.setAttribute('onclick', "getChannel('General');"); - button.innerHTML = list[i]; - document.querySelector('#channels').append(button); - } // end for - - - - - - // OLD - REMOVE Add Channel - change "new channel" to this - adds a channel to channel list - socket.on('add channel', data => { - - console.log("Processing server response..."); - const contents = `${data.channel}`; - - // Create new channel item for list - const li = document.createElement('li'); - li.innerHTML = contents; - - // Add new item to list - document.querySelector('#channelList').append(li); - - // Clear input field - document.querySelector('#channel').value = ''; }); - // When a new channel is announced, add to channel list - socket.on('add channel', data => { - console.log("Adding channel...", data); - - // remove any old lists - var myList = document.getElementById('channels'); - .innerHTML = ''; - -
  • - # General -
  • + socket.on('update channels', data => { + // debug info + console.log("UPDATE CHANNEL: " + data['channel']); + // should be channel list + for (let i = 0; i < data['channel'].length; i++) { + console.log("update channel list", data['channel'][i]); + channelList[i] = data['channel'][i]; + } + buildChannelList(activeChannel); - //add_channel(data["channel"], 0); }); -*/ // Add Message - add a new message coming in and add to display list socket.on('add message', data => { console.log("Adding message...", data); let messageCount = parseInt(localStorage.getItem('message-count')); - // build the datetime for the posted message - let d = new Date(); - let year = d.getFullYear(); - let month = months[d.getMonth()]; - let day = d.getDate(); - let hours = d.getHours(); - let minutes = d.getMinutes(); - - // make human readable 12 hour format - let ampm = hours >= 12 ? 'PM' : 'AM'; - hours = hours % 12; - hours = hours ? hours : 12; // '0' hour is '12' - minutes = minutes < 10 ? '0' + minutes : minutes; - let time = hours + ':' + minutes + ' ' + ampm; + // building a bootstrap formatted user message let msgHeader = "
    "; - let msgIdentifier = data["username"]+" | "+time+" | "+month+" "+day+", "+year; + let msgIdentifier = data["username"]+data["datetime"]; let msgSeperator = "

    "; let msgTrailer = "


    "; - let msg = msgHeader + msgIdentifier + msgSeperator + data["message"] + msgTrailer + let msg = msgHeader + msgIdentifier + msgSeperator + data["message"] + msgTrailer; let li = document.createElement('li'); li.setAttribute('class',"list-group-item"); @@ -287,7 +261,7 @@ document.addEventListener('DOMContentLoaded', () => { // we have a user in the dict to process if (data.hasOwnProperty(key)) { - console.log("KEY VALUE: ",data[key]) + console.log("KEY VALUE: ",data[key]); // build a bootstrap formatted user list let li = document.createElement('li'); From 635ca412191a6579372b1b21e6723cdc23a842c3 Mon Sep 17 00:00:00 2001 From: "A. Hoyt" Date: Sun, 24 Mar 2019 22:51:16 -0400 Subject: [PATCH 13/24] More fixes - behavior ok on Chrome, but spurious on Firefox and Safari - will spend more time to debug --- application.py | 48 +++++++++++++++++++++++++----------------------- static/Index.js | 34 ++++++++++------------------------ 2 files changed, 35 insertions(+), 47 deletions(-) diff --git a/application.py b/application.py index 2626ca8..9be187e 100644 --- a/application.py +++ b/application.py @@ -32,24 +32,31 @@ def connect(data): global channels messages = [] - # get server date / time - current = datetime.datetime.now() - # check if channels empty - first time through if not channels: + # get server date / time + current = datetime.datetime.now() + + displayHeader = " | "+str(current.hour)+":"+str(current.minute)+" | "+str(current.month)+" "+str(current.day)+", "+str(current.year) # always provide a general channel just like slack messages.insert(0, {'username': "System", 'channel': "General", - 'datetime': current.__str__(), # use dunder method to convert to json + 'datetime': displayHeader, 'message': "Welcome to Flack!"}) + channels['General'] = messages - print("Channels after connecting: ", channels) - emit("select channel", channels, broadcast=False) + emit("select channel", channels, broadcast=True) else: # already have some channels so communicate - print(channels) - emit("select channel", channels, broadcast=False) + updatedChannels = [] + + # extract updated list of channels + for key in channels.keys(): + updatedChannels.append(key) + + # emit current channel list + emit("update channels", {'channel': updatedChannels}, broadcast=True) # check if user already connected if (data["username"] not in users.values()): @@ -71,14 +78,16 @@ def connect(data): @socketio.on('get channel') def getChannel(data): global channels + updatedChannels = [] # emit current channel list - emit("select channel", channels, broadcast=False) + emit("select channel", channels, broadcast=True) @socketio.on('new channel') def addChannel(data): global channels updatedChannels = [] + # add the new channel to the server channel list channels.update({data['channel']: []}) @@ -86,9 +95,6 @@ def addChannel(data): for key in channels.keys(): updatedChannels.append(key) - # dump debug data - print("1: ", updatedChannels) - # let everyone know a new channel is available emit("update channels", {'channel': updatedChannels}, broadcast=True) @@ -96,16 +102,12 @@ def addChannel(data): def addMessage(data): global channels - print("2: ", data) - print("3: ", channels) - channels.setdefault(data['channel'], []).append(data) - print("4: ", channels) - - # need to add message to channels array here - #updatedChannels.append(data) - + # add the message, but keep lists (message queue) to 100 + if len(channels[data['channel']]) > MESSAGELIMIT: + channels.setdefault(data['channel'], []).append(data) + channels.setdefault(data['channel'], []).pop(0) + else: + channels.setdefault(data['channel'], []).append(data) - print(data["username"], data["channel"], data["datetime"], data["message"]) - messages.append(data) - print(messages) + # notify everyone of new message emit("add message", data, broadcast=True) diff --git a/static/Index.js b/static/Index.js index 52c16bc..295531a 100644 --- a/static/Index.js +++ b/static/Index.js @@ -15,6 +15,7 @@ function selectChannel(channelName) { // make sure messages are going to the right channel activeChannel = channelName; + localStorage.setItem('channel', activeChannel); // source of truth is on the server - request message for the selected channel socket.emit('get channel', {'channel': channelName}); @@ -27,23 +28,23 @@ function loadChannel() { if (!localStorage.getItem('channel')) { localStorage.setItem('channel', "General"); activeChannel = "General"; - channelList.push(activeChannel); } else { // otherwise we load previous activeChannel = localStorage.getItem('channel'); } + socket.emit('get channel', {'channel': activeChannel}); } // builds the channel list function buildChannelList(activeChannel) { - console.log("buildChannel"); + console.log("buildChannel - length = "+channelList.length); // clear channels var userList = document.getElementById('channels'); channels.innerHTML = ''; // loop through channel list - set active channel for (let i = 0; i < channelList.length; i++) { - + console.log("constructing channel list..."); // building a bootstrap formatted channel list let button = document.createElement('button'); if (channelList[i] == activeChannel) { @@ -57,6 +58,7 @@ function buildChannelList(activeChannel) { console.log("BUTTON: ", button); document.querySelector('#channels').append(button); } + console.log("something went wrong...."); } // build current message list - user selected another channel @@ -73,21 +75,20 @@ function buildMessageList(messageList) { // building a bootstrap formatted user message let msgHeader = "
    "; - let msgIdentifier = messageList[i]["username"] + messageList[i]["datetime"]; - let msgSeperator = "

    "; - let msgTrailer = "


    "; - let msg = msgHeader + msgIdentifier + msgSeperator + messageList[i]["message"] + msgTrailer; - let li = document.createElement('li'); - li.setAttribute('class', "list-group-item"); + // setting message display attributes + li.setAttribute('class', "list-group-item"); li.setAttribute('id', "posted-message-" +i ); li.innerHTML = msg; + document.querySelector('#messages').append(li); + + // adjust view to keep current postings visible let element = document.getElementById("posted-message-" + i); element.scrollIntoView(); } @@ -184,23 +185,8 @@ document.addEventListener('DOMContentLoaded', () => { let messageList = data[activeChannel]; console.log("MESSAGE LIST: ", messageList); buildMessageList(messageList); - - /* console.log("SELECT CHANNEL: "+activeChannel ); - for (let i = 0; i < data[activeChannel].length; i++) { - console.log("channel messages", data[activeChannel][i]); - = data[activeChannel][i] - } - console.log("CHANNEL: "+data['channel']); - // console.log("DATA FROM SELECT channel: "+data['messages']); - // should be channel list - for (let i = 0; i < channelList.length; i++) { - console.log("SELECT CHANNEL"+i+": ", channelList[i]) - } -*/ buildChannelList(activeChannel); - // extract channel messages and populate page - //let messages = data['messages']; }); socket.on('update channels', data => { From 75ab8a8a0afb64c16cf88d9301aa5ec59ca0f9f0 Mon Sep 17 00:00:00 2001 From: "A. Hoyt" Date: Mon, 25 Mar 2019 00:21:40 -0400 Subject: [PATCH 14/24] More updates and fixes from testing with Chrome and Firefox --- README.md | 32 +++++++++++++++++++--- application.py | 6 ++--- static/Index.js | 71 ++++++++++++++++++++++++++----------------------- 3 files changed, 69 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index e3d97e9..f22f2ca 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,35 @@ # Project 2 README.md file -Web Programming with Python and JavaScript +Web Programming with Python and JavaScript Project 2 - Flack -1) App uses pop-ups to prompt user for username and channels so browser must not block pop-ups for proper functionality +Flack is a simple messaging application that allows users to join with a display name, create / join channels (chat rooms) and post messages. To post a message, simply select a channel and enter text in the message box located at the bottom of the screen and press the "Post" button. + +Personal Touch: + + +1) The application uses pop-ups to prompt user for display name and channel names so your browser MUST allow pop-ups for proper functionality + +2) To add channels select the plus (+) icon next to "Channels" - the "General" channel is provided by default just like Slack + +3) New users joining the app are displayed in the left side Users column + +4) The application has been tested mostly on chrome and some on Firefox. + +Key files and resources: +application.py - primary flack application that serves the index.html file and then starts managing the websocket connections. + +index.js - + +index.html - + +static resources: +addGraphic.png +favicon.ico +flackUser.png +style.css - mostly focused on configuring the messages + +requirements.txt -2) To add channels select the plus (+) icon next to "Channels" -3) New users joining the app are displayed in the Users column \ No newline at end of file diff --git a/application.py b/application.py index 9be187e..98b8f83 100644 --- a/application.py +++ b/application.py @@ -1,6 +1,6 @@ import os import datetime -from flask import Flask, render_template, redirect, request, jsonify, request, flash, url_for, session +from flask import Flask, render_template from flask_socketio import SocketIO, emit app = Flask(__name__) @@ -46,7 +46,7 @@ def connect(data): 'message': "Welcome to Flack!"}) channels['General'] = messages - emit("select channel", channels, broadcast=True) + emit("select channel", channels, broadcast=False) else: # already have some channels so communicate updatedChannels = [] @@ -81,7 +81,7 @@ def getChannel(data): updatedChannels = [] # emit current channel list - emit("select channel", channels, broadcast=True) + emit("select channel", channels, broadcast=False) @socketio.on('new channel') def addChannel(data): diff --git a/static/Index.js b/static/Index.js index 295531a..fd2733a 100644 --- a/static/Index.js +++ b/static/Index.js @@ -11,7 +11,7 @@ var months = ["January", "February", "March", "April", "May", "June", "July", // prompt user via popup to enter a new channel function selectChannel(channelName) { - console.log("selectChannel" + channelName); + console.log("selectChannel: " + channelName); // make sure messages are going to the right channel activeChannel = channelName; @@ -21,6 +21,7 @@ function selectChannel(channelName) { socket.emit('get channel', {'channel': channelName}); } + // load prior channel state - part of project requirements function loadChannel() { console.log("loadChannel"); @@ -35,6 +36,7 @@ function loadChannel() { socket.emit('get channel', {'channel': activeChannel}); } + // builds the channel list function buildChannelList(activeChannel) { console.log("buildChannel - length = "+channelList.length); @@ -61,6 +63,7 @@ function buildChannelList(activeChannel) { console.log("something went wrong...."); } + // build current message list - user selected another channel function buildMessageList(messageList) { console.log("Building message: ", messageList ); @@ -94,6 +97,7 @@ function buildMessageList(messageList) { } } + // add channel from prompt function addChannel() { console.log("addChannel"); @@ -141,6 +145,7 @@ function loadUsername() { } } +// main document event handler document.addEventListener('DOMContentLoaded', () => { // when connected @@ -181,18 +186,22 @@ document.addEventListener('DOMContentLoaded', () => { }); socket.on('select channel', data => { - + console.log("SELECT: ", data); let messageList = data[activeChannel]; - console.log("MESSAGE LIST: ", messageList); + + // extract keys to buld channel list + const keys = Object.keys(data); + for (let i = 0; i < keys.length; i++) { + console.log("update channel list", keys[i]); + channelList[i] = keys[i]; + } buildMessageList(messageList); buildChannelList(activeChannel); }); socket.on('update channels', data => { - - // debug info - console.log("UPDATE CHANNEL: " + data['channel']); + console.log("UPDATE: ", data); // should be channel list for (let i = 0; i < data['channel'].length; i++) { @@ -203,35 +212,31 @@ document.addEventListener('DOMContentLoaded', () => { }); - // Add Message - add a new message coming in and add to display list + // Post a single message - adding to selected display list socket.on('add message', data => { console.log("Adding message...", data); - let messageCount = parseInt(localStorage.getItem('message-count')); - - - - // building a bootstrap formatted user message - let msgHeader = "
    "; - - let msgIdentifier = data["username"]+data["datetime"]; - - let msgSeperator = "

    "; - - let msgTrailer = "


    "; - - let msg = msgHeader + msgIdentifier + msgSeperator + data["message"] + msgTrailer; - - let li = document.createElement('li'); - li.setAttribute('class',"list-group-item"); - - li.setAttribute('id',"posted-message-"+messageCount); - li.innerHTML = msg; - document.querySelector('#messages').append(li); - document.querySelector("#"+data["username"]).innerHTML = messageCount+1; - let element = document.getElementById("posted-message-"+messageCount); - element.scrollIntoView(); - localStorage.setItem('message-count', messageCount+1); + if (data['channel'] == activeChannel) { + let messageCount = parseInt(localStorage.getItem('message-count')); + + // building a bootstrap formatted user message + let msgHeader = "
    "; + let msgIdentifier = data["username"] + data["datetime"]; + let msgSeperator = "

    "; + let msgTrailer = "


    "; + let msg = msgHeader + msgIdentifier + msgSeperator + data["message"] + msgTrailer; + let li = document.createElement('li'); + + // set attributes + li.setAttribute('class', "list-group-item"); + li.setAttribute('id', "posted-message-" + messageCount); + li.innerHTML = msg; + document.querySelector('#messages').append(li); + document.querySelector("#" + data["username"]).innerHTML = messageCount + 1; + let element = document.getElementById("posted-message-" + messageCount); + element.scrollIntoView(); + localStorage.setItem('message-count', messageCount + 1); + } }); // Add User - when a new user is announced, add to global userList From f663bba02243ebdedcde18f1350ce1ca1077ed65 Mon Sep 17 00:00:00 2001 From: "A. Hoyt" Date: Mon, 25 Mar 2019 08:36:28 -0400 Subject: [PATCH 15/24] Updated README.md --- README.md | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index f22f2ca..660d30e 100644 --- a/README.md +++ b/README.md @@ -1,34 +1,34 @@ # Project 2 README.md file -Web Programming with Python and JavaScript Project 2 - Flack + ### Flack Overview: +Flack is a simple messaging application that allows users to register with a display name, create / join channels (chat rooms) and post messages. To post a message, a user simply selects (or creates) a channel and enters text in the message box located at the bottom of the screen. Pressing the "Post" button, adds the message to the active lists and updates anyone else in the channel -Flack is a simple messaging application that allows users to join with a display name, create / join channels (chat rooms) and post messages. To post a message, simply select a channel and enter text in the message box located at the bottom of the screen and press the "Post" button. +##Personal Touch: +The personal touch includes the addition of messages badges in the user list that tracks and displays the number of messages posted by each user -Personal Touch: +##Notes: - -1) The application uses pop-ups to prompt user for display name and channel names so your browser MUST allow pop-ups for proper functionality +1) The application uses pop-ups to prompt the user for their display name and channel - the browser MUST allow pop-ups for proper functionality of the application 2) To add channels select the plus (+) icon next to "Channels" - the "General" channel is provided by default just like Slack 3) New users joining the app are displayed in the left side Users column -4) The application has been tested mostly on chrome and some on Firefox. +4) The application has been tested mostly on Chrome and some on Firefox. + +##Key files and resources: +1) application.py - primary flack application that serves the index.html file, tracks channels / messages and manages user websocket connections. -Key files and resources: -application.py - primary flack application that serves the index.html file and then starts managing the websocket connections. +2) index.js - client side javascript file which is the core of this application. Handles client interactions with the server via websockets -index.js - +3) index.html - the single page application screen base on boostrap -index.html - +4) static resources - this includes the index.html file (mentioned above), three graphic files (addGraphic.png, +favicon.ico, and flackUser.png) and the style.css which is mostly used to to properly configure messages -static resources: -addGraphic.png -favicon.ico -flackUser.png -style.css - mostly focused on configuring the messages +5) requirements.txt - a list of dependent python modules necessary for running the server -requirements.txt +6) README.md - this file From ef2448d2f6175622c40e807b4944acaf1074ba65 Mon Sep 17 00:00:00 2001 From: ah0yt <32006324+ah0yt@users.noreply.github.com> Date: Mon, 25 Mar 2019 08:39:18 -0400 Subject: [PATCH 16/24] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 660d30e..9b5de37 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Flack is a simple messaging application that allows users to register with a d ##Personal Touch: The personal touch includes the addition of messages badges in the user list that tracks and displays the number of messages posted by each user -##Notes: +## Notes: 1) The application uses pop-ups to prompt the user for their display name and channel - the browser MUST allow pop-ups for proper functionality of the application @@ -16,7 +16,7 @@ The personal touch includes the addition of messages badges in the user list tha 4) The application has been tested mostly on Chrome and some on Firefox. -##Key files and resources: +## Key files and resources: 1) application.py - primary flack application that serves the index.html file, tracks channels / messages and manages user websocket connections. 2) index.js - client side javascript file which is the core of this application. Handles client interactions with the server via websockets @@ -32,4 +32,4 @@ favicon.ico, and flackUser.png) and the style.css which is mostly used to to pro - \ No newline at end of file + From 92712b2edfa17320305b3406dbca1088551aa485 Mon Sep 17 00:00:00 2001 From: ah0yt <32006324+ah0yt@users.noreply.github.com> Date: Mon, 25 Mar 2019 08:45:20 -0400 Subject: [PATCH 17/24] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 9b5de37..9a0ca42 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,8 @@ The personal touch includes the addition of messages badges in the user list tha ## Key files and resources: 1) application.py - primary flack application that serves the index.html file, tracks channels / messages and manages user websocket connections. +![display name prompt](https://user-images.githubusercontent.com/32006324/54920669-2c9f8680-4eda-11e9-9885-10319313668f.jpg) + 2) index.js - client side javascript file which is the core of this application. Handles client interactions with the server via websockets 3) index.html - the single page application screen base on boostrap From e390d06a8eb6695077f919733b24447638160550 Mon Sep 17 00:00:00 2001 From: ah0yt <32006324+ah0yt@users.noreply.github.com> Date: Mon, 25 Mar 2019 08:46:58 -0400 Subject: [PATCH 18/24] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9a0ca42..27a321f 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,9 @@ The personal touch includes the addition of messages badges in the user list tha ## Notes: -1) The application uses pop-ups to prompt the user for their display name and channel - the browser MUST allow pop-ups for proper functionality of the application +1) The application uses pop-ups to prompt the user for their display name and channel - the browser MUST allow pop-ups for proper functionality of the application. Here is what the prompt looks like: + +![display name prompt](https://user-images.githubusercontent.com/32006324/54920669-2c9f8680-4eda-11e9-9885-10319313668f.jpg) 2) To add channels select the plus (+) icon next to "Channels" - the "General" channel is provided by default just like Slack @@ -19,8 +21,6 @@ The personal touch includes the addition of messages badges in the user list tha ## Key files and resources: 1) application.py - primary flack application that serves the index.html file, tracks channels / messages and manages user websocket connections. -![display name prompt](https://user-images.githubusercontent.com/32006324/54920669-2c9f8680-4eda-11e9-9885-10319313668f.jpg) - 2) index.js - client side javascript file which is the core of this application. Handles client interactions with the server via websockets 3) index.html - the single page application screen base on boostrap From 8fe81dc242461949c1f8897c30f5162779982220 Mon Sep 17 00:00:00 2001 From: ah0yt <32006324+ah0yt@users.noreply.github.com> Date: Mon, 25 Mar 2019 08:56:41 -0400 Subject: [PATCH 19/24] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 27a321f..50fd808 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ The personal touch includes the addition of messages badges in the user list tha 1) The application uses pop-ups to prompt the user for their display name and channel - the browser MUST allow pop-ups for proper functionality of the application. Here is what the prompt looks like: -![display name prompt](https://user-images.githubusercontent.com/32006324/54920669-2c9f8680-4eda-11e9-9885-10319313668f.jpg) + 2) To add channels select the plus (+) icon next to "Channels" - the "General" channel is provided by default just like Slack From a49f5dd19eb6503fc38d3e9effd2642f83d54d2c Mon Sep 17 00:00:00 2001 From: ah0yt <32006324+ah0yt@users.noreply.github.com> Date: Mon, 25 Mar 2019 08:56:58 -0400 Subject: [PATCH 20/24] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 50fd808..7e8c134 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ The personal touch includes the addition of messages badges in the user list tha 1) The application uses pop-ups to prompt the user for their display name and channel - the browser MUST allow pop-ups for proper functionality of the application. Here is what the prompt looks like: - + 2) To add channels select the plus (+) icon next to "Channels" - the "General" channel is provided by default just like Slack From 8be06151286eb441f232298b3538f3c64e625c68 Mon Sep 17 00:00:00 2001 From: ah0yt <32006324+ah0yt@users.noreply.github.com> Date: Mon, 25 Mar 2019 08:57:17 -0400 Subject: [PATCH 21/24] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7e8c134..54144c9 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ The personal touch includes the addition of messages badges in the user list tha 1) The application uses pop-ups to prompt the user for their display name and channel - the browser MUST allow pop-ups for proper functionality of the application. Here is what the prompt looks like: - + 2) To add channels select the plus (+) icon next to "Channels" - the "General" channel is provided by default just like Slack From 716a311bd1ddfd9fe98c95c2e32994f43838327c Mon Sep 17 00:00:00 2001 From: ah0yt <32006324+ah0yt@users.noreply.github.com> Date: Mon, 25 Mar 2019 11:22:10 -0400 Subject: [PATCH 22/24] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 54144c9..8790ac0 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,8 @@ The personal touch includes the addition of messages badges in the user list tha 3) New users joining the app are displayed in the left side Users column + + 4) The application has been tested mostly on Chrome and some on Firefox. ## Key files and resources: From 7f3ea66ae2da79d128a03cc300d5ea98da39add4 Mon Sep 17 00:00:00 2001 From: ah0yt <32006324+ah0yt@users.noreply.github.com> Date: Mon, 25 Mar 2019 11:22:32 -0400 Subject: [PATCH 23/24] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8790ac0..f09d2a7 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ The personal touch includes the addition of messages badges in the user list tha 1) The application uses pop-ups to prompt the user for their display name and channel - the browser MUST allow pop-ups for proper functionality of the application. Here is what the prompt looks like: - + 2) To add channels select the plus (+) icon next to "Channels" - the "General" channel is provided by default just like Slack From 77a4cc290487e51c554d0cf970c03b8a10c0dcdd Mon Sep 17 00:00:00 2001 From: ah0yt <32006324+ah0yt@users.noreply.github.com> Date: Mon, 25 Mar 2019 11:22:48 -0400 Subject: [PATCH 24/24] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f09d2a7..07acafc 100644 --- a/README.md +++ b/README.md @@ -10,13 +10,13 @@ The personal touch includes the addition of messages badges in the user list tha 1) The application uses pop-ups to prompt the user for their display name and channel - the browser MUST allow pop-ups for proper functionality of the application. Here is what the prompt looks like: - + 2) To add channels select the plus (+) icon next to "Channels" - the "General" channel is provided by default just like Slack 3) New users joining the app are displayed in the left side Users column - + 4) The application has been tested mostly on Chrome and some on Firefox.