I have a problem sorting the users based on their karma. Can you guys please help? (site: here) I want to sort the div elements of the users according to totalKarma. Also is there a good method for refreshing the data in the background so it doesn't have to load the whole page (like the user icons).
var leaderboard = document.getElementById('leaderboard');
var commentKarma;
var postKarma;
var userName;
var userIcon;
var userUrl;
var usersloaded = [];
var userskarma = [];
var usersIcon = [];
var users = ['sloth_on_meth','filiptronicek','cigarkovic','gallowboob','tooshiftyforyou','actually_crazy_irl','haxpress'];
function updateStats() {
leaderboard.innerHTML = '';
users.forEach(mainfunc);
}
updateStats();
function mainfunc(user) {
$.getJSON('https://www.reddit.com/user/' + user + '/about.json', function(data) {
commentKarma = data.data.comment_karma;
postKarma = data.data.link_karma;
totalKarma = commentKarma + postKarma;
userName = user;
userIcon = data.data.icon_img;
userUrl = 'https://reddit.com/u/' + userName;
leaderboard.innerHTML +=
"<div class='usr' id='" +
userName +
"'><br><br><img src='" +
userIcon +
"'><br><a href='" +
userUrl +
"'> u/" +
userName +
'</a><br>' +
totalKarma.toLocaleString() +
' karma';
usersloaded.push(user);
userskarma.push(totalKarma);
usersIcon.push(userIcon);
// console.log(user);
// console.log(usersIcon);
userskarma.sort(function(a, b) {
return a - b;
});
// console.log(userskarma);
})
.done(function() {
return;
})
.fail(function() {
console.log('error loading ' + user);
})
.always(function() {
// console.log('completed loading ' + user);
});
}
#import url('https://fonts.googleapis.com/css?family=Roboto');
* {
margin: 0;
padding: 0;
}
.usr {
width: 150px;
height: 35px;
padding: 4.5em;
padding-bottom: 250px;
}
#leaderboard {
width: 95%;
height: 35px;
padding: 0.5em;
}
#leaderboard>div {
float: left;
}
img {
border-radius: 10px;
}
a {
text-decoration: none;
color: #ff4500;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<body>
<div id="leaderboard">
</div>
</body>
You could do something like this. Create an array usersloaded with user objects with userName, userIcon, userUrl etc properties. Then, it'll be easier for you sort the objects based on the totalKarma property and create the HTML as you're doing before.
var leaderboard = document.getElementById('leaderboard');
var commentKarma;
var postKarma;
var userName;
var userIcon;
var userUrl;
var usersloaded = [];
users = [
'sloth_on_meth',
'filiptronicek',
'cigarkovic',
'gallowboob',
'tooshiftyforyou',
'actually_crazy_irl',
'haxpress'
];
function updateStats() {
leaderboard.innerHTML = '';
users.forEach(mainfunc);
}
updateStats();
function mainfunc(user) {
$.getJSON('https://www.reddit.com/user/' + user + '/about.json', function(data) {
commentKarma = data.data.comment_karma;
postKarma = data.data.link_karma;
totalKarma = commentKarma + postKarma;
userName = user;
userIcon = data.data.icon_img;
userUrl = 'https://reddit.com/u/' + userName;
usersloaded.push({
user,
userName,
userIcon,
userUrl,
totalKarma
});
loadData(usersloaded);
})
.done(function() {
return;
})
.fail(function() {
console.log('error loading ' + user);
})
.always(function() {
//console.log('completed loading ' + user);
});
}
function loadData(usersloaded) {
leaderboard.innerHTML = ''
usersloaded.sort((a, b) => a.totalKarma - b.totalKarma)
.forEach(u => {
leaderboard.innerHTML +=
"<div class='usr' id='" +
u.userName +
"'><br><br><img src='" +
u.userIcon +
"'><br><a href='" +
u.userUrl +
"'> u/" +
u.userName +
'</a><br>' +
u.totalKarma.toLocaleString() +
' karma';
})
}
#import url('https://fonts.googleapis.com/css?family=Roboto');
* {
margin: 0;
padding: 0;
}
.usr {
width: 150px;
height: 35px;
padding: 4.5em;
padding-bottom: 250px;
}
#leaderboard {
width: 95%;
height: 35px;
padding: 0.5em;
}
#leaderboard>div {
float: left;
}
img {
border-radius: 10px;
}
a {
text-decoration: none;
color: #ff4500;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="leaderboard">
</div>
Your code is not attempting to rearrange the divs, it's just appending to the body as the requests come back. At a high level, you need to create an array of objects, sort them and print them after they have been sorted.
Note that I have made minimal changes to your code to get it working, but you would benefit from a code review
var leaderboard = document.getElementById('leaderboard');
var commentKarma;
var postKarma;
var userName;
var userIcon;
var userUrl;
var usersloaded = [];
var userskarma = [];
var usersIcon = [];
users = [
'sloth_on_meth',
'filiptronicek',
'cigarkovic',
'gallowboob',
'tooshiftyforyou',
'actually_crazy_irl',
'haxpress'
];
var userObjs = [];
function updateStats() {
leaderboard.innerHTML = '';
users.forEach(mainfunc);
}
updateStats();
function mainfunc(user) {
$.getJSON('https://www.reddit.com/user/' + user + '/about.json', function(data) {
commentKarma = data.data.comment_karma;
postKarma = data.data.link_karma;
totalKarma = commentKarma + postKarma;
userName = user;
userIcon = data.data.icon_img;
userUrl = 'https://reddit.com/u/' + userName;
userObjs.push({
commentKarma,
postKarma,
totalKarma,
userName,
userIcon,
userUrl
});
if (userObjs.length == users.length) {
userObjs.sort((a, b) => a.totalKarma - b.totalKarma);
leaderboard.innerHTML = userObjs.map(user => {
return "<div class='usr' id='" +
user.userName +
"'><br><br><img src='" +
user.userIcon +
"'><br><a href='" +
user.userUrl +
"'> u/" +
user.userName +
'</a><br>' +
user.totalKarma.toLocaleString() +
' karma';
}).join("");
}
leaderboard.innerHTML +=
"<div class='usr' id='" +
userName +
"'><br><br><img src='" +
userIcon +
"'><br><a href='" +
userUrl +
"'> u/" +
userName +
'</a><br>' +
totalKarma.toLocaleString() +
' karma';
usersloaded.push(user);
userskarma.push(totalKarma);
usersIcon.push(userIcon);
console.log(user);
console.log(usersIcon);
userskarma.sort(function(a, b) {
return a - b;
});
console.log(userskarma);
//setTimeout(function(){ updateStats(); }, 10000);
})
.done(function() {
return;
})
.fail(function() {
console.log('error loading ' + user);
})
.always(function() {
console.log('completed loading ' + user);
});
}
#import url('https://fonts.googleapis.com/css?family=Roboto');
* {
margin: 0;
padding: 0;
}
body {
background: black;
color: white;
font-family: Roboto;
font-weight: bold;
text-transform: uppercase;
font-size: 2vh;
}
.usr {
width: 150px;
height: 35px;
padding: 4.5em;
padding-bottom: 250px;
}
#leaderboard {
width: 95%;
height: 35px;
padding: 0.5em;
}
#leaderboard>div {
float: left;
}
img {
border-radius: 10px;
}
a {
text-decoration: none;
color: #ff4500;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Reddit karma</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" media="screen" href="style.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</head>
<body>
<div id="leaderboard">
</div>
</body>
</html>
Related
class GenerateArray {
constructor() {
this.arrayCode = document.getElementById('code');
this.BaseCode = document.getElementById('preCode');
this.startCode = document.getElementById('startC');
this.endCode = document.getElementById('endC');
this.question = "";
this.prefix = "";
this.description = "";
this.answer = "";
this.id = "";
this.Name = "";
this.answerDIV = "";
this.count = 0;
}
generateQuestionPart() {
this.question = document.createElement('input');
this.question.setAttribute('type', 'text');
this.question.id = 'question' + this.count;
this.question.className = 'question';
this.question.placeholder = 'What is the question?'
this.prefix = document.createElement('input');
this.prefix.setAttribute('type', 'text');
this.prefix.className = 'prefix';
this.prefix.id = 'prefix' + this.count;
this.prefix.placeholder = 'The prefix of the question that belongs to the link'
this.description = document.createElement('input');
this.description.setAttribute('type', 'text');
this.description.id = 'description' + this.count;
this.description.className = 'description';
this.description.placeholder = 'Add the description that is going to be in the info pop up';
this.answerDIV = document.createElement('div');
this.answerDIV.className = 'answerDIV' + this.count;
this.answerDIV.id = 'AnswerDivId';
this.answer = document.createElement('button');
this.answer.setAttribute('type', 'button');
this.answer.id = 'answer';
this.answer.className = 'answerN' + this.count;
this.answer.innerHTML = 'Add Answer';
this.answer.onclick = function (e) {
for (let i = 0; i < NewArray.count; i++) {
if (e.target.className.endsWith(i)) {
NewArray.id = document.createElement('input');
NewArray.id.setAttribute('type', 'text');
NewArray.id.id = 'id' + i;
NewArray.id.classList.add('id');
NewArray.id.placeholder = 'Add the ID of the answer';
NewArray.Name = document.createElement('input');
NewArray.Name.setAttribute('type', 'text');
NewArray.Name.id = 'Name' + i;
NewArray.Name.className = 'name';
NewArray.Name.placeholder = 'Add the text that is on the answer button';
// console.log(e.target.className);
document.getElementsByClassName('answerDIV' + i)[0].appendChild(NewArray.id);
document.getElementsByClassName('answerDIV' + i)[0].appendChild(NewArray.Name);
}
}
}
document.getElementsByClassName('create')[0].appendChild(this.question);
document.getElementsByClassName('create')[0].appendChild(this.prefix);
document.getElementsByClassName('create')[0].appendChild(this.description);
document.getElementsByClassName('create')[0].appendChild(this.answerDIV);
document.getElementsByClassName('create')[0].appendChild(this.answer);
this.count++;
// console.log(NewArray.answer.length)
}
writeArray() {
let basis = document.createElement('p');
basis.innerHTML =
" class QuizPart {\n" +
" constructor(questionText, chosenAnswer, prefix, questionDescription) {\n" +
" this.questionText = questionText;\n" +
" this.chosenAnswer = chosenAnswer;\n" +
" this.prefix = prefix;\n" +
" this.questionDescription = questionDescription;\n" +
" }\n" +
" }\n" +
"\n" +
" class ChosenAnswer {\n" +
" constructor(id, name) {\n" +
" this.id = id;\n" +
" this.name = name;\n" +
" }\n" +
" }";
this.BaseCode.appendChild(basis);
let startC = document.createElement('p');
startC.innerHTML = "let Quiz = [";
for (let i = 0; i < this.count; i++) {
let code = document.createElement('p');
let output = "new QuizPart('" + document.getElementById('question' + i).value + "', [";
let answers = document.querySelectorAll("input#Name" + i)
console.log(answers.length);
for (let y = 0; y < answers.length; y++) {
output += "new ChosenAnswer('" + document.getElementById('id' + i).value + "', '" + document.getElementById('Name' + i).value + "'),"
}
output += "], '" + document.getElementById('prefix' + i).value + "',";
output += "'" + document.getElementById('description' + i).value + "',";
code.innerHTML = output;
this.arrayCode.appendChild(code);
}
let endC = document.createElement('p');
endC.innerHTML = "]"
this.startCode.appendChild(startC);
this.endCode.appendChild(endC);
// console.log(this.count.length);
}
}
NewArray = new GenerateArray();
NewArray.generateQuestionPart();
body {
margin: 0;
padding: 0;
}
.container{
height: 1000px;
width: 800px;
position: relative;
margin-top: 5px;
left: 50%;
-ms-transform: translate(-50%, 5%);
transform: translate(-50%, 5%);
}
.QPB{
width: 50px;
height: 50px;
margin-bottom: 10px;
background-color: orange;
font-size: 40px;
}
.question{
width: 100%;
height: 20px;
margin-bottom: 10px;
}
#answer{
width: 100px;
height: 35px;
margin-bottom: 50px;
}
.prefix{
width: 100%;
height: 20px;
margin-bottom: 10px;
}
.description{
width: 100%;
height: 20px;
margin-bottom: 10px;
}
.id{
position: relative;
width: 90%;
height: 20px;
margin-bottom: 10px;
margin-left: 10%;
}
.name{
position: relative;
width: 90%;
height: 20px;
margin-bottom: 20px;
margin-left: 10%;
}
.CreateArray{
width: 100px;
height: 35px;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="./style.css">
<title>Hoi</title>
</head>
<body>
<div class="container">
<div class="create">
<button id="QuestionPartBtn" class="QPB" type="button" onclick="NewArray.generateQuestionPart()">+</button>
</div>
<div class="result">
<button id="CreateArray" class="CreateArray" type="button" onclick="NewArray.writeArray()">Create Array</button>
</div>
<div class="preCode" id="preCode"></div>
<div class="startC" id="startC"></div>
<div class="code" id="code"></div>
<div class="endC" id="endC"></div>
</div>
I created this system that makes an array with information that a user fills in in input fields.
The input fields are dynamically generated, so I use a for loop to show them all in an innerHTML that eventually creates the array.
My code:
this.answerDIV = document.createElement('div');
this.answerDIV.className = 'answerDIV' + this.count;
this.answerDIV.id = 'AnswerDivId';
this.answer = document.createElement('button');
this.answer.setAttribute('type', 'button');
this.answer.id = 'answer';
this.answer.className = 'answerN' + this.count;
this.answer.innerHTML = 'Add Answer';
this.answer.onclick = function (e) {
for (let i = 0; i < NewArray.count; i++) {
if (e.target.className.endsWith(i)) {
NewArray.id = document.createElement('input');
NewArray.id.setAttribute('type', 'text');
NewArray.id.id = 'id' + i;
NewArray.id.classList.add('id');
NewArray.id.placeholder = 'Add the ID of the answer';
NewArray.Name = document.createElement('input');
NewArray.Name.setAttribute('type', 'text');
NewArray.Name.id = 'Name' + i;
NewArray.Name.className = 'name';
NewArray.Name.placeholder = 'Add the text that is on the answer button';
// console.log(e.target.className);
document.getElementsByClassName('answerDIV' + i)[0].appendChild(NewArray.id);
document.getElementsByClassName('answerDIV' + i)[0].appendChild(NewArray.Name);
}
}
}
For loop:
for (let i = 0; i < this.count; i++) {
let code = document.createElement('p');
let output = "new QuizPart('" + document.getElementById('question' + i).value + "', [";
let answers = document.querySelectorAll("input#Name" + i)
console.log(answers.length);
for (let y = 0; y < answers.length; y++) {
output += "new ChosenAnswer('" + document.getElementById('id' + i).value + "', '" + document.getElementById('Name' + i).value + "'),"
}
output += "], '" + document.getElementById('prefix' + i).value + "',";
output += "'" + document.getElementById('description' + i).value + "',";
code.innerHTML = output;
this.arrayCode.appendChild(code);
}
The problem is with the second loop. Whenever I create 3 input fields for one question and I generate the innerHTML code it does show me all 3, except that they are all the first input field and the second and third aren't used as seen in the following screenshot:The problem
if i change i to y: Problem 2
(My FiddleJS link):https://jsfiddle.net/thijsl0705/1s98gumk/1/
I entered a,b,c then add answer, d,e then hit the plus sign and add f,g,h,i,j then create array. then hit the plus sign and add 1,2,3,4,5 and create the array and get:
let Quiz = [
let Quiz = [
new QuizPart('a', [new ChosenAnswer('d', 'e'),], 'b','c',
new QuizPart('f', [new ChosenAnswer('i', 'j'),], 'g','h',
new QuizPart('a', [new ChosenAnswer('d', 'e'),], 'b','c',
new QuizPart('f', [new ChosenAnswer('i', 'j'),], 'g','h',
new QuizPart('1', [new ChosenAnswer('4', '5'),], '2','3',
]
]
what exactly is the problem? what do you want to do? Looks like you might be missing a closing ) for each new QuizPart
I'm having trouble customizing this code to have a bubble chat icon that stays within my website when I scroll down. Anyone with an idea of how I can improve it?
Here is my code so far:
<!-- Add this script tag without any modification to the target webpage -->
<script type="application/javascript">
var ciscoBubbleChat = (function() {
var smHost = 'socialminer.uonbi.ac.ke';
var widgetId = '1';
var msgMustAcceptCert = 'Certificate must be accepted to start the conversation.';
var msgAcceptCertButtonLabel = 'Accept Certificate';
var msgCloseButtonLabel = 'Close';
var msgWaitingCertAcceptance = 'Waiting for certificate acceptance.';
var msgConnectivityIssues = 'We are experiencing connectivity issues. Try later.';
var appId = 'cisco_bubble_chat';
var appMargin = 15;
var appUrl = 'https://' + smHost + '/ccp/ui/BubbleChat.html?host=' + smHost + '&wid=' + widgetId;
var connectivityCheckUrl = 'https://' + smHost + '/ccp/ui/ConnectivityCheck.html';
var messageEventListener;
var addNoCacheQueryParam;
return {
showChatWindow: function(injectedData) {
var logPrefix = 'CISCO_BUBBLE_CHAT: ';
if (document.getElementById(appId)) {
console.log(logPrefix + 'Not loading BubbleChat as it is already loaded');
return;
}
var validateInjectedData = function(formData) {
// browser compatible way to check whether it is an object with 10 fields and all the values are strings
var result = true;
if (formData && typeof formData === 'object' && formData.constructor === Object) {
var counter = 0;
for (var key in formData) {
if (!(typeof formData[key] === 'string' || formData[key] instanceof String)) {
result = false;
break;
}
counter++;
if (counter > 10) {
result = false;
break;
}
}
} else {
result = false;
}
return result;
};
if (injectedData) {
if (validateInjectedData(injectedData.formData)) {
appUrl += '&injectedFormData=' + encodeURIComponent(JSON.stringify(injectedData.formData));
} else {
if (typeof injectedData.validationErrorCallback === 'function') {
injectedData.validationErrorCallback();
} else {
console.log(logPrefix + 'Could not invoke validationErrorCallback as it is not a function');
}
}
}
var iframe = document.createElement('iframe');
iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin allow-forms allow-popups');
iframe.setAttribute('id', appId);
iframe.setAttribute('style', 'position: fixed; width: 312px; height: 410px; border: none; bottom: 0px; right: 0; z-index:999;');
document.body.appendChild(iframe);
var frameWindow = iframe.contentWindow ? iframe.contentWindow : iframe;
var frameDoc = frameWindow.document;
// Trigger a page load for iframe inline content loading to work in Firefox
frameDoc.open();
frameDoc.close();
frameDoc.body.innerHTML = '<div id="secure-connectivity-check-container" style="position: fixed; width: 300px; height: 395px; ' +
'bottom: 10px; right: 10px; font-family: Helvetica; font-size: 14px; color: #4F5051;' +
'box-shadow: 0 0 3px #000; background: #fff; display: flex; flex-direction: column; display: none;">' +
'<div style="height: 25%;"></div>' +
'<div style="height: 25%; display: flex; align-items: flex-start; justify-content: center; text-align: center;">' +
'<div style="padding: 0 15% 0 15%;">' +
'<div id="secure-connectivity-check-msg"></div>' +
'<a id="accept-cert-button" style="display:none; padding-top: 10px" href="#" onclick="acceptCertificate(); return void(0);">' +
msgAcceptCertButtonLabel +
'</a>' +
'</div>' +
'</div>' +
'<div style="height: 25%; display: flex; align-items: flex-end; justify-content: center; text-align: center;">' +
'<div style="padding: 0 15% 0 15%;">' +
'<a href="#" onclick="window.parent.postMessage({messageType: \'unmount\'}, \'*\'); return void(0);">' +
msgCloseButtonLabel +
'</a>' +
'</div>' +
'</div>' +
'<div style="height: 25%;"></div>' +
'</div>';
frameWindow.acceptCertificate = function() {
frameDoc.getElementById('secure-connectivity-check-msg').innerHTML = msgWaitingCertAcceptance;
frameDoc.getElementById('accept-cert-button').style.display = 'none';
window.open(addNoCacheQueryParam(connectivityCheckUrl), 'SM_CERT_PAGE');
};
if (!addNoCacheQueryParam) {
addNoCacheQueryParam = function(url) {
return url + (url.indexOf("?") === -1 ? '?' : '&') + 'nocache=' + new Date().getTime();
}
}
if (!messageEventListener) {
messageEventListener = function(event) {
console.log(logPrefix + 'Received event from origin: ' + event.origin);
console.log(logPrefix + 'Received event data: ' + JSON.stringify(event.data));
switch (event.data.messageType) {
case 'resize':
document.getElementById(appId).style.height = event.data.height + appMargin + 'px';
console.log(logPrefix + 'Successfully resized');
break;
case 'unmount':
document.body.removeChild(document.getElementById(appId));
window.removeEventListener('message', messageEventListener);
console.log(logPrefix + 'Successfully unmounted BubbleChat and removed event listener for message');
break;
case 'bubblechat-cert-accepted':
document.getElementById(appId).setAttribute('src', addNoCacheQueryParam(appUrl));
console.log(logPrefix + 'Successfully validated certificate acceptance and loaded BubbleChat');
break;
default:
console.log(logPrefix + 'Unknown message type');
}
};
}
window.addEventListener('message', messageEventListener);
console.log(logPrefix + 'Event listener for message added');
// Check HTTPS connectivity and show appropriate screen
var showConnectivityIssue = function(message, showAcceptCertLink) {
window.postMessage({
messageType: 'resize',
height: 395
}, '*');
frameDoc.getElementById('secure-connectivity-check-container').style.display = 'block';
frameDoc.getElementById('secure-connectivity-check-msg').innerHTML = message;
frameDoc.getElementById('accept-cert-button').style.display = showAcceptCertLink ? 'block' : 'none';
};
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (this.readyState === 4) {
console.log(logPrefix + 'Connectivity check status: ' + this.status);
switch (this.status) {
case 200:
iframe.setAttribute('src', addNoCacheQueryParam(appUrl));
break;
case 0:
showConnectivityIssue(msgMustAcceptCert, true);
break;
default:
showConnectivityIssue(msgConnectivityIssues, false);
}
}
};
console.log(logPrefix + 'Checking connectivity to: ' + connectivityCheckUrl);
xhr.open('GET', addNoCacheQueryParam(connectivityCheckUrl), true);
xhr.send();
}
};
})();
</script>
<!--
Use the function 'ciscoBubbleChat.showChatWindow() as the event handler for initiating chat.
eg: <button onclick="ciscoBubbleChat.showChatWindow()">Start Chat</button>
Optionally, invisible form data can be submitted, which will be submitted along with the fields customer fills in.
Upto 10 fields can be passed. If more than 10 fields are passed, the invisible form data will not be used and
the provided error callback will be invoked. For injecting form data, an object should be passed to
ciscoBubbleChat.showChatWindow() as an argument. The object should be of the form:
{
formData: {
InjectedField1: 'InjectedValue1',
InjectedField2: 'InjectedValue2'
...
},
validationErrorCallback: function(){console.log('business specific logic goes here');}
}
The form data can have any string as field name and value. The submitted invisible form data values will be
shown in the agent desktop, as well as will be updated in ContextService if the specified fieldset(s) in the widget
contains these field names just like the regular visible chat form fields data.
eg:
<button onclick="ciscoBubbleChat.showChatWindow({
formData: {
AnyFieldName1: 'AnyFieldValue1',
AnyFieldName2: 'AnyFieldValue2',
AnyFieldName3: 'AnyFieldValue3',
AnyFieldName4: 'AnyFieldValue4',
AnyFieldName5: 'AnyFieldValue5',
AnyFieldName6: 'AnyFieldValue6',
AnyFieldName7: 'AnyFieldValue7',
AnyFieldName8: 'AnyFieldValue8',
AnyFieldName9: 'AnyFieldValue9',
AnyFieldName10: 'AnyFieldValue10'
},
validationErrorCallback: function(){console.log('error in validating injected data');}
})">Click to chat</button>
-->
<html>
<body>
<button class onclick="ciscoBubbleChat.showChatWindow()">Start Chat</button>
</body>
</html>
I want to customize it so that it can have a better look, and find a way to keep it within my website. Does anyone have any ideas?
The best solution would be to add position: fixed; on the button, for example: <button style="position: fixed; bottom: 0; right: 0;" onclick="ciscoBubbleChat.showChatWindow()">Start Chat</button> That would force the button to stay on the lower right side of screen at all times. And for the icon, just add an <img> tag.
Demo:
.chatBtn {
position: fixed;
bottom: 20px;
right: 20px;
z-index: 2;
}
.chatBtn img {
width: 40px; /* Change this to what you want. */
height: 40px; /* Change this to what you want. */
}
<button class="chatBtn" onclick="ciscoBubbleChat.showChatWindow()"><img src="https://icon-library.com/images/talk-bubble-icon-png/talk-bubble-icon-png-2.jpg"> <!-- You can put your own image here. -->
</button>
<!-- Add this script tag without any modification to the target webpage -->
<script type="application/javascript">
var ciscoBubbleChat = (function () {
var smHost = 'socialminer.uonbi.ac.ke';
var widgetId = '1';
var msgMustAcceptCert = 'Certificate must be accepted to start the conversation.';
var msgAcceptCertButtonLabel = 'Accept Certificate';
var msgCloseButtonLabel = 'Close';
var msgWaitingCertAcceptance = 'Waiting for certificate acceptance.';
var msgConnectivityIssues = 'We are experiencing connectivity issues. Try later.';
var appId = 'cisco_bubble_chat';
var appMargin = 15;
var appUrl = 'https://' + smHost + '/ccp/ui/BubbleChat.html?host=' + smHost + '&wid=' + widgetId;
var connectivityCheckUrl = 'https://' + smHost + '/ccp/ui/ConnectivityCheck.html';
var messageEventListener;
var addNoCacheQueryParam;
return {
showChatWindow: function (injectedData) {
var logPrefix = 'CISCO_BUBBLE_CHAT: ';
if (document.getElementById(appId)) {
console.log(logPrefix + 'Not loading BubbleChat as it is already loaded');
return;
}
var validateInjectedData = function(formData) {
// browser compatible way to check whether it is an object with 10 fields and all the values are strings
var result = true;
if (formData && typeof formData === 'object' && formData.constructor === Object){
var counter = 0;
for (var key in formData) {
if (!(typeof formData[key] === 'string' || formData[key] instanceof String)) {
result = false;
break;
}
counter++;
if (counter > 10) {
result = false;
break;
}
}
} else {
result = false;
}
return result;
};
if (injectedData) {
if (validateInjectedData(injectedData.formData)) {
appUrl += '&injectedFormData=' + encodeURIComponent(JSON.stringify(injectedData.formData));
} else {
if (typeof injectedData.validationErrorCallback === 'function') {
injectedData.validationErrorCallback();
} else {
console.log(logPrefix + 'Could not invoke validationErrorCallback as it is not a function');
}
}
}
var iframe = document.createElement('iframe');
iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin allow-forms allow-popups');
iframe.setAttribute('id', appId);
iframe.setAttribute('style', 'position: fixed; width: 312px; height: 410px; border: none; bottom: 0px; right: 0; z-index:999;');
document.body.appendChild(iframe);
var frameWindow = iframe.contentWindow ? iframe.contentWindow : iframe;
var frameDoc = frameWindow.document;
// Trigger a page load for iframe inline content loading to work in Firefox
frameDoc.open();
frameDoc.close();
frameDoc.body.innerHTML = '<div id="secure-connectivity-check-container" style="position: fixed; width: 300px; height: 395px; ' +
'bottom: 10px; right: 10px; font-family: Helvetica; font-size: 14px; color: #4F5051;' +
'box-shadow: 0 0 3px #000; background: #fff; display: flex; flex-direction: column; display: none;">' +
'<div style="height: 25%;"></div>' +
'<div style="height: 25%; display: flex; align-items: flex-start; justify-content: center; text-align: center;">' +
'<div style="padding: 0 15% 0 15%;">' +
'<div id="secure-connectivity-check-msg"></div>' +
'<a id="accept-cert-button" style="display:none; padding-top: 10px" href="#" onclick="acceptCertificate(); return void(0);">' +
msgAcceptCertButtonLabel +
'</a>' +
'</div>' +
'</div>' +
'<div style="height: 25%; display: flex; align-items: flex-end; justify-content: center; text-align: center;">' +
'<div style="padding: 0 15% 0 15%;">' +
'<a href="#" onclick="window.parent.postMessage({messageType: \'unmount\'}, \'*\'); return void(0);">' +
msgCloseButtonLabel +
'</a>' +
'</div>' +
'</div>' +
'<div style="height: 25%;"></div>' +
'</div>';
frameWindow.acceptCertificate = function () {
frameDoc.getElementById('secure-connectivity-check-msg').innerHTML = msgWaitingCertAcceptance;
frameDoc.getElementById('accept-cert-button').style.display = 'none';
window.open(addNoCacheQueryParam(connectivityCheckUrl), 'SM_CERT_PAGE');
};
if (!addNoCacheQueryParam){
addNoCacheQueryParam = function (url) {
return url + (url.indexOf("?") === -1 ? '?' : '&') + 'nocache=' + new Date().getTime();
}
}
if (!messageEventListener) {
messageEventListener = function (event) {
console.log(logPrefix + 'Received event from origin: ' + event.origin);
console.log(logPrefix + 'Received event data: ' + JSON.stringify(event.data));
switch (event.data.messageType) {
case 'resize':
document.getElementById(appId).style.height = event.data.height + appMargin + 'px';
console.log(logPrefix + 'Successfully resized');
break;
case 'unmount':
document.body.removeChild(document.getElementById(appId));
window.removeEventListener('message', messageEventListener);
console.log(logPrefix + 'Successfully unmounted BubbleChat and removed event listener for message');
break;
case 'bubblechat-cert-accepted':
document.getElementById(appId).setAttribute('src', addNoCacheQueryParam(appUrl));
console.log(logPrefix + 'Successfully validated certificate acceptance and loaded BubbleChat');
break;
default:
console.log(logPrefix + 'Unknown message type');
}
};
}
window.addEventListener('message', messageEventListener);
console.log(logPrefix + 'Event listener for message added');
// Check HTTPS connectivity and show appropriate screen
var showConnectivityIssue = function (message, showAcceptCertLink) {
window.postMessage({ messageType: 'resize', height: 395 }, '*');
frameDoc.getElementById('secure-connectivity-check-container').style.display = 'block';
frameDoc.getElementById('secure-connectivity-check-msg').innerHTML = message;
frameDoc.getElementById('accept-cert-button').style.display = showAcceptCertLink ? 'block' : 'none';
};
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (this.readyState === 4) {
console.log(logPrefix + 'Connectivity check status: ' + this.status);
switch (this.status) {
case 200:
iframe.setAttribute('src', addNoCacheQueryParam(appUrl));
break;
case 0:
showConnectivityIssue(msgMustAcceptCert, true);
break;
default:
showConnectivityIssue(msgConnectivityIssues, false);
}
}
};
console.log(logPrefix + 'Checking connectivity to: ' + connectivityCheckUrl);
xhr.open('GET', addNoCacheQueryParam(connectivityCheckUrl), true);
xhr.send();
}
};
})();
</script>
<!--
Use the function 'ciscoBubbleChat.showChatWindow() as the event handler for initiating chat.
eg: <button onclick="ciscoBubbleChat.showChatWindow()">Start Chat</button>
Optionally, invisible form data can be submitted, which will be submitted along with the fields customer fills in.
Upto 10 fields can be passed. If more than 10 fields are passed, the invisible form data will not be used and
the provided error callback will be invoked. For injecting form data, an object should be passed to
ciscoBubbleChat.showChatWindow() as an argument. The object should be of the form:
{
formData: {
InjectedField1: 'InjectedValue1',
InjectedField2: 'InjectedValue2'
...
},
validationErrorCallback: function(){console.log('business specific logic goes here');}
}
The form data can have any string as field name and value. The submitted invisible form data values will be
shown in the agent desktop, as well as will be updated in ContextService if the specified fieldset(s) in the widget
contains these field names just like the regular visible chat form fields data.
eg:
<button onclick="ciscoBubbleChat.showChatWindow({
formData: {
AnyFieldName1: 'AnyFieldValue1',
AnyFieldName2: 'AnyFieldValue2',
AnyFieldName3: 'AnyFieldValue3',
AnyFieldName4: 'AnyFieldValue4',
AnyFieldName5: 'AnyFieldValue5',
AnyFieldName6: 'AnyFieldValue6',
AnyFieldName7: 'AnyFieldValue7',
AnyFieldName8: 'AnyFieldValue8',
AnyFieldName9: 'AnyFieldValue9',
AnyFieldName10: 'AnyFieldValue10'
},
validationErrorCallback: function(){console.log('error in validating injected data');}
})">Click to chat</button>
-->
EDIT:
A chat bubble icon has been added.
I am trying to fetch programs by search of query (name of show) through the Gracenote API.
For reference:
http://developer.tmsapi.com/io-docs (v1.1/programs/search)
Using the example (to fetch movies) listed on their website, it works fine.
http://developer.tmsapi.com/Sample_Code
<html>
<head>
<style type="text/css">
.tile {
display: inline-block;
border: 2px;
padding: 4px;
text-align: left;
font-size: 15px;
width:250px;
font-family: Avenir;
color: white;
}
</style>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script>
// construct the url with parameter values
var apikey = "xxxxx";
var baseUrl = "http://data.tmsapi.com/v1.1";
var showtimesUrl = baseUrl + '/movies/showings';
var zipCode = "78701";
var d = new Date();
var today = d.getFullYear() + '-' + (d.getMonth()+1) + '-' + d.getDate();
$(document).ready(function() {
// send off the query
$.ajax({
url: showtimesUrl,
data: { startDate: today,
zip: zipCode,
jsonp: "dataHandler",
api_key: apikey
},
dataType: "jsonp",
});
});
// callback to handle the results
function dataHandler(data) {
$(document.body).append('<h2>Found ' + data.length + ' movies showing within 5 miles of ' + zipCode+'</h2>');
$.each(data, function(index, movie) {
var movieData = '<div class="tile"><img src="http://fanc.tmsimg.com/' + movie.preferredImage.uri + '?api_key='+apikey+'"><br/>';
movieData += 'Title:' + movie.title + '<br>';
movieData += 'ID: ' + movie.tmsId + '<br>';
if (movie.ratings) {movieData += 'Rating: ' + movie.ratings[0].code;}
else {movieData += 'Rating: ' + 'N/A';}
$(document.body).append(movieData);
});
}
</script>
</head>
<body>
</body>
</html>
When I am trying to modify it (to fetch programs), I fail to retrieve any data, all returned as undefined.
<html>
<head>
<style type="text/css">
.tile {
display: inline-block;
border: 2px;
padding: 4px;
text-align: left;
font-size: 15px;
width:250px;
font-family: Avenir;
color: white;
}
</style>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script>
// construct the url with parameter values
var apikey = "xxxxx";
var baseUrl = "http://data.tmsapi.com/v1.1";
var showtimesUrl = baseUrl + '/programs/search';
var zipCode = "78701";
var showName = 'Friends';
$(document).ready(function() {
// send off the query
$.ajax({
url: showtimesUrl,
data: { q: showName,
jsonp: "dataHandler",
api_key: apikey
},
dataType: "jsonp",
});
});
// callback to handle the results
function dataHandler(data) {
$(document.body).append('<h2>Found ' + data.length + ' movies showing within 5 miles of ' + zipCode+'</h2>');
var programs = data.hits;
$.each(data, function(index, program) {
var programData = '<div class="tile">' + program.entityType + '<br/>';
programData += 'Title:' + program.title + '<br>';
programData += 'ID: ' + program.tmsId + '<br>';
$(document.body).append(programData);
});
}
</script>
</head>
<body>
</body>
</html>
Actual result: (Response Status: 200)
undefined
Title: undefined
ID: undefined
Expected result: (Response Status: 200)
Show
Title: Friends
ID: SH001151270000
I was able to sort it out by looking at the array.
For the Movies sample code provided by the website the array returned a property path as [""0""].entityType but for Program it is returned as hits[""0""].program.entityType.
So I replaced data with data.hits and program.entityType with program.program.entityType etc.
function dataHandler(data) {
$(document.body).append('<h2>Found ' + data.hits.length + ' shows.</h2>');
$.each(data.hits, function(index, program) {
var programData = '<div class="tile">' + program.program.entityType + '<br/>';
programData += 'Title:' + program.program.title + '<br>';
programData += 'ID: ' + program.program.tmsId + '<br>';
$(document.body).append(programData);
});
}
I am trying to show <Candidate></Candidate> in Rutland County with only votes higher than 0. Right now it shows them all just in Rutland County.
https://jsfiddle.net/jeffd/yqbwaxts/3/
https://99centbeats.com/ResultsData.xml
So Far:
$(document).ready(function() {
$.ajax({
type: 'GET',
url: 'https://99centbeats.com/ResultsData.xml',
//url: 'https://vtelectionresults.sec.state.vt.us/rss/2713/ResultsData.xml',
crossDomain: true,
success: parseXml
});
});
function parseXml(xml) {
$(xml).find('Town').each(function() {
var county = $(this).find('County').text(); //change to county for 'County'
window.votes = $(this).find('Votes').text();
if (county == 'RUTLAND') { // change to 'RUTLAND' for Rutland County
if (votes !== '0'){
window.townname = $(this).find('TownName').text();
window.officename = $(this).find('OfficeName, Name, Votes');
var newItems = $.map(officename, function(i) {
$(i).filter('0')
return $(i).text();
});
newItems2 = ("" + newItems).replace(/,/g, " - ");
$(".marquee").append(' - <strong>' + townname + '</strong>' + ' - ' + newItems2);
}
}
});
$('.marquee').marquee({
duration: 5000 // Speed of the counter (Lower = Faster)
});
}
setTimeout(function() {
window.location.reload(1);
}, 300000); // Refresh Results Every 5 Minutes
It seems like you're going at this rather haphazardly, just grabbing elements and stringing them together. It's better to methodically get the offices within a town, then their candidates, then filter those candidates by votes, etc.
The following should work, though it seems that there's currently only one candidate in one Rutland town that has any votes:
//Must have Allow-Control-Allow-Origin chrome plugin installed to work
$(document).ready(function() {
$.ajax({
type: 'GET',
url: 'https://99centbeats.com/ResultsData.xml',
//url: 'https://vtelectionresults.sec.state.vt.us/rss/2713/ResultsData.xml',
crossDomain: true,
success: parseXml
});
});
function textForOffice(office) {
var candidates = $(office).find('Candidate').filter(function(i, el) {
return $(el).find('Votes').text() > 0;
});
if (candidates.length === 0) {
return '';
}
var officeName = $(office).find('OfficeName').text();
var candidateValues = candidates.toArray().map(function (el) {
return $(el).find('Name').text() + ' - ' + $(el).find('Votes').text();
});
return ' - ' + officeName + ' - ' + candidateValues.join(' - ');
}
function parseXml(xml) {
$(xml).find('Town').each(function() {
var town = $(this);
var county = town.find('County').text(); //change to county for 'County'
if (county == 'RUTLAND') { // change to 'RUTLAND' for Rutland County
var townname = town.find('TownName').text();
var offices = town.find('Office');
var textForOffices = offices.toArray().map(textForOffice);
$(".marquee").append(' - <strong>' + townname + '</strong>' + textForOffices.join(''));
}
});
$('.marquee').marquee({
duration: 5000 // Speed of the counter (Lower = Faster)
});
}
setTimeout(function() {
window.location.reload(1);
}, 300000); // Refresh Results Every 5 Minutes
.rssfeed {
background-color: black;
color: white;
bottom: 0;
font-family: Gotham, Helvetica Neue, Helvetica, Arial, " sans-serif";
height: 150px;
line-height: 150px;
font-size: 32px;
}
.marquee {
overflow: hidden;
width: 100%;
white-space: nowrap;
}
.description {
width: 100%;
height: 50px;
background: red;
color: white;
line-height: 50px;
text-align: center;
font-family: Gotham, "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 24px;
}
<div class="description">Rutland City - Vote Count Per Ward</div>
<div class="rssfeed">
<div class="marquee"></div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/jquery.marquee/1.4.0/jquery.marquee.min.js"></script>
In this coding I showed progress bar on the text box. but i need loading indicator in span tag when searching for something. I added two images to better understand about it. please answer me the question.
this is flat progress in text box:
but i need the progress on span
CSS:
<style type="text/css">
.loader
{
background: url(resources/images/loader.gif);
background-repeat: no-repeat;
background-position: right;
}
</style>
JS:
try {
console.log('connections url ' , urlHolder.getconnectedusersByName);
$("#auto-complete-tag").autocomplete({
source: function(request, respond) {
$("#auto-complete-tag").addClass('loader');
var givenUserName = $("#auto-complete-tag").val();
$.post(urlHolder.getconnectedusersByName, {
userId : signedUserId,
username : givenUserName
}, function(response) {
$('#auto-complete-tag').removeClass('loader');
if(!response){
respond([]);
length = 0;
}
this.connectionsList = new Array();
for (var counter = 0; counter < response.users.length; counter++) {
var getConnectedUsers = new Object();
getConnectedUsers = {
value : response.users[counter].name,
//profileId : "onclick=return false",
image : response.users[counter].defaultImageFileName,
id:response.users[counter].id
}
this.connectionsList.push(getConnectedUsers);
}
respond (this.connectionsList);
});
},
delay: 0 ,
search: function (e, u) {
},
select : function(event, ui) {
return false;
},
response: function(event, ui) {
length = ui.content.length;
console.log('length',length );
if(length === 0) {
var noResult = {label:"No results found for you" };
ui.content.push(noResult);
}
},
}) .data('ui-autocomplete')._renderItem = function(ul, item) {
if(length !== 0){
return $('<li>')
.data( "ui-autocomplete-item", item)
.append(
'<a style="background-color: #E0F0EF; color:#0d78a3; margin-bottom: 3px; margin-top: 3px; margin-left: 3px; margin-right: 3px; font-weight: bold;">' +
'<span style="color:#86BBC9; font-weight: normal;">' +
item.label + '</span>' + '<br>'+'<span>Text message</span>'+
'<button style="margin-bottom:14px; margin-right:5px;" class=\"yellow-btn apply-btn\" id=\"apply-user-' + item.id + '\" onclick=\"openDFAChatWithUser(\'' + item.id + '\')\">Chat</button>'
+ '<span class="ui-autocomplete-icon pull-right"></span>' +
'</a>'
)
.appendTo(ul);}else{
return $('<li>')
.data( "ui-autocomplete-item", item)
.append('<a>' +
'<span class="ui-autocomplete-user">' +
item.label + '</span>' +
'<span class="ui-autocomplete-divider"></span>' +
'<span class="ui-autocomplete-icon pull-right"></span>' +
'</a>')
.appendTo(ul);
}
};
//console.log(' this.connectionsList >>> ', this.connectionsList);
} catch (e) {
console.log('getAllConnections error >>> ', e);
}