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.
Related
I’m working with SharePoint and I’m able to load content from a library and display it on a webpage as a link, using REST API. I figured out a way to arrange the content in the order the documents are uploaded into the folder by the “Created Date”, displaying the last uploaded item on top. However, I feel there is a more efficient way of performing this action. The script I hacked together seem to work on occasion. Sometimes it will appear to be out of the sequence but when I refresh the browser it will return it in the items in the desire sequence. Below is the code I’m using to accomplish this task. If there is a better way of accomplishing this action will greatly be appreciated.
<ul id="column1">
<h2 id="newsletter"><img style="width: 40px; position: relative; right: 5px; top: 7px;" src="../SiteAssets/SitePages/Test Page/icons/DCSA_Portal_Newsletter.svg" alt="logo">Newsletter<img id="arrow1" src="../SiteAssets/SitePages/Test Page/icons/arrow.png" alt="logo"></h2>
<ol></ol>
</ul>
getFilesFromFolder("/sites/dcsa/ep/epMainFiles/News/Newsletter").done(function(data) {
$.each(data.d.results, function(i, item) {
var spDate = new Date(item.TimeCreated.split('T')[0]) //example: '2015-10-30T05:00:00Z'
var newTillDate = new Date();
spDate.setDate(spDate.getDate() + 5);
if (spDate <= newTillDate) {
$("#column1 ol").append('<li class="linkData newsletter" style="padding-left: 10px; padding-right: 10px;" data-date="' + item.TimeCreated.split('T')[0] + '">' + item.Name.replace(/\.[^/.]+$/, "") + " - " + '<span style="color: red;">' + item.TimeCreated.split('T')[0] + '</span>' + '</li>');
} else {
$("#column1 ol").append('<li class="linkData newsletter" style="padding-left: 10px; padding-right: 10px;" data-date="' + item.TimeCreated.split('T')[0] + '"><img class="newArrow" style="width: 60px; position: relative; right: 5px; top: 0px;"src="../SiteAssets/SitePages/Test Page/icons/arrow-with_new2.gif" alt="logo">' + item.Name.replace(/\.[^/.]+$/, "") + " - " + '<span style="color: red;">' + item.TimeCreated.split('T')[0] + '</span>' + '</li>');
}
col1_chgOrder();
});
});
function col1_chgOrder() {
var container = $("#column1 ol");
var items = $("#column1 ol .linkData");
items.each(function() {
// Convert the string in 'data-event-date' attribute to a more
// standardized date format
var BCDate = $(this).attr("data-date");
/*console.log(BCDate);
var standardDate = BCDate[1]+" "+BCDate[0]+" "+BCDate[2];*/
var standartDate = new Date(BCDate).getTime();
$(this).attr("data-event-date", standartDate);
//console.log(standartDate);
});
items.sort(function(a, b) {
a = parseFloat($(a).attr("data-event-date"));
b = parseFloat($(b).attr("data-event-date"));
return a < b ? -1 : a > b ? 1 : 0;
}).each(function() {
container.prepend(this);
});
}
function getFilesFromFolder(serverRelativeUrlToFolder) {
return $.ajax({
url: _spPageContextInfo.webAbsoluteUrl + "/_api/web/GetFolderByServerRelativeUrl('" + serverRelativeUrlToFolder + "')/files",
method: "GET",
async: false,
headers: {
"Accept": "application/json; odata=verbose"
}
});
}
you could include orderby filter in your API endpoint url rather than doing sorting after response is received.
url: _spPageContextInfo.webAbsoluteUrl + "/_api/web/GetFolderByServerRelativeUrl('" + serverRelativeUrlToFolder + "')/files?&$orderby=Created desc
i.e. you don't need to use col1_chgOrder() function as API will return files already sorted due to this parameter
Use Jsom to get files by caml query with order.
<script type="text/javascript">
$(function () {
ExecuteOrDelayUntilScriptLoaded(retrieveFiles, "sp.js");
})
function retrieveFiles() {
var ctx = SP.ClientContext.get_current();
var docLib = ctx.get_web().get_lists().getByTitle("MyDoc");
var camlQuery = new SP.CamlQuery();
camlQuery.set_viewXml(
"<View Scope='RecursiveAll'><Query><OrderBy><FieldRef Name=\"Created\" Ascending=\"False\"/></OrderBy></Query></View>");
camlQuery.set_folderServerRelativeUrl("/MyDoc/FolderA");
var Files = docLib.getItems(camlQuery);
ctx.load(Files);
ctx.executeQueryAsync(Function.createDelegate(this, function () {
var listItemEnumerator = Files.getEnumerator();
while (listItemEnumerator.moveNext()) {
var oListItem = listItemEnumerator.get_current();
alert(oListItem.get_id());
}
}), Function.createDelegate(this, function () {
alert('error');
}));
}
</script>
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>
I'm writing a remote/in-browser logging tool (basically an in browser console so I can remote debug mobile devices and whatnot) and I am having trouble printing/accessing some raw DOM elements and objects (They appear to be objects when I log them to the console). When call bronsole (don't judge me) on the event object some of the DOM objects are not being looped through as if the for loop doesn't recognise it as an object. One of the objects in question is the HTMLpropertiescollection. I don't have any particular need for this oject specifically but I am logging touch events and it would be nice to be able to read all of the properties of the event object.
(function ($) {
$('body').prepend('<div id="eoenuitn345n34ntdhiu45dnth" style="position: fixed; top:0; left: 0; width: 100%; height: 100px; background-color: rgba(0,0,0,0.5); z-index: 1000000; overflow-y: auto; padding-top: 40px;"><div id="seouihtoeuitnei98e797etuiST" style="position:absolute; top: 5px; right: 5px; background-color: #C0504D; height: 20px; width: 20px;"></div></div>');
$('#eoenuitn345n34ntdhiu45dnth').click(function(e){
if($(this).height() <= 150){
$(this).animate({height: '100%'});
}else{
$(this).animate({height: '150px'});
}
});
$('#seouihtoeuitnei98e797etuiST').click(function(e){
e.stopPropagation();
if($(this).parent().height() <= 30){
$(this).parent().animate({height: '100%'});
}else{
$(this).parent().animate({height: '0px'});
}
});
$('#eoenuitn345n34ntdhiu45dnth').on('click','.oseu098oaeuno7e089',function(e){
e.stopPropagation();
if($(this).height() > 15){
$(this).css('height', '15px');
$.each($(this).children('.oseu098oaeuno7e089'), function(){
$(this).css('height', '15px');
});
}else{
$(this).css('height', 'auto');
}
if($('#eoenuitn345n34ntdhiu45dnth').height() <= 100){
$('#eoenuitn345n34ntdhiu45dnth').animate({height: '100%'});
}
});
$('#eoenuitn345n34ntdhiu45dnth').on('click','.oeusn0eui0HTDRh98oeui',function(e){
e.stopPropagation();
});
window.uonteuho8o6e8ued68uou8Color = ['#6BC3FF','#FF494F','#00D3D3','#77FF6B','#DBD300','#D470FF'];
var entityMap = {
"&": "&",
"<": "<",
">": ">",
'"': '"',
"'": ''',
"/": '/'
};
function escapeHtml(string) {
return String(string).replace(/[&<>"'\/]/g, function (s) {
return entityMap[s];
});
}
function htmlConsole(param){
var obj = (typeof param.NTDNTH8oe8uidu98NT != 'undefined') ? param.NTDNTH8oe8uidu98NT : param;
var index = (typeof param.sjtnhxsSTHxsnheu9isTH != 'undefined') ? param.sjtnhxsSTHxsnheu9isTH : null;
var preKey = (typeof param.sntuhinegdukx0euetkhe989 != 'undefined') ? '[' + param.sntuhinegdukx0euetkhe989 + ']: ' : '';
var spaceAdd = (typeof param.sNDGHBn788rnFI9 != 'undefined') ? param.sNDGHBn788rnFI9 + '____' : '';
var depth = (typeof param.netnuxie0xbenuihtdNT09 != 'undefined') ? param.netnuxie0xbenuihtdNT09 + 1 : '0';
var element = '';
if(typeof obj != null){
if(typeof obj == 'string' || typeof obj == 'number' || typeof obj == 'boolean'){
element += ('<p class="oeusn0eui0HTDRh98oeui" style="color: white; padding:2px;margin:2px; background-color: orange;"><span style="visibility:hidden">' + spaceAdd + '</span>' + preKey + escapeHtml(String(obj)) + '</p>');
}else{
var end = ('<p style="color: white; padding:2px;margin:2px;"><span style="visibility:hidden">' + spaceAdd + '</span>' + ')</p></div>');
element += ('<div id="oestniSTHSseti897e_' + depth + '" class="oseu098oaeuno7e089" style="color: white; padding:2px;margin:2px; height: 15px; overflow:hidden; cursor: pointer; background-color: ' + window.uonteuho8o6e8ued68uou8Color[depth%6] + '"><span style="visibility:hidden">' + spaceAdd + '</span>' + preKey + Object.prototype.toString.call( obj ) + '(<br>');
if(Object.prototype.toString.call( obj ) == '[object Function]'){
element += ('<p class="oeusn0eui0HTDRh98oeui" style="color: white; padding:2px;margin:2px; background-color: orange;"><span style="visibility:hidden">' + spaceAdd + '___' + '</span>' + escapeHtml(String(obj)) + '</p>');
}
if(depth < 10){ // this is because I fudge up the script with "too much recursion" on big objects. I'm in the middle of solving this, hence the redundant properties
for(var key in obj){
element += htmlConsole({NTDNTH8oe8uidu98NT: obj[key], sNDGHBn788rnFI9: spaceAdd, sntuhinegdukx0euetkhe989: key,netnuxie0xbenuihtdNT09: depth,sjtnhxsSTHxsnheu9isTH: index}).element;
}
}else{
element += end;
return {element: element, obj:obj};
}
element += end;
}
}
return {element: element};
}
$.bronsole = function(obj){
$('#eoenuitn345n34ntdhiu45dnth').prepend(htmlConsole(obj).element);
};
$.fn.bronsole = function(text){
var _this = this;
if(typeof text != 'undefined'){
$('#eoenuitn345n34ntdhiu45dnth').prepend(htmlConsole(text).element);
}
$('#eoenuitn345n34ntdhiu45dnth').prepend(htmlConsole(_this).element);
return this;
};
}( jQuery ));
We're working on a JavaScript project with the Leap Motion controller. The code was working fine this morning, but, six hours later, it is now dysfunctional, erratic, and unresponsive. We put in alerts to see up until when it stops running, and it stops running when it reaches Leap.loop; we think the problem is something somewhere is becoming overloaded, but we don't know programming enough to actually have a grasp of what's wrong. We've tried it on different hardware (different servers and different local drives), and the only response we're getting is the "Some webpages are unresponsive. Kill or Ignore?" popup.
<title>THIS SUCKS</title>
<style>
html, body {
width: 100%;
height:100%;
margin: 0;
padding: 0;
background: #024;
color: #fff;
}
#wrap {
width: 600px;
margin: 0 auto;
}
.half {
width: 50%;
margin-top: 100px;
float: left;
}
div {
text-align: center;
font-size: 60px;
font-family: Helvetica, Arial, sans-serif;
}
#hands,
#fingers {
font-weight: bold;
font-size: 200px;
}
</style>
<script src="//js.leapmotion.com/0.2.0-beta1/leap.min.js"></script>
<div id="gestureData"></div>
<script>
// Store frame for motion functions
var previousFrame = null;
// Setup Leap loop with frame callback function
var controllerOptions = {enableGestures: true};
var url = "";
try {
request = new XMLHttpRequest();
} catch (trymicrosoft) {
try {
request = new ActiveXObject("Msxml2.XMLHTTP");
} catch (othermicrosoft) {
try {
request = new ActiveXObject("Microsoft.XMLHTTP");
} catch (failed) {
request = false;
}
}
}
Leap.loop(controllerOptions, function(frame) {
// Display Gesture object data
var gestureOutput = document.getElementById("gestureData");
var gestureString = "";
if (frame.gestures.length > 0) {
for (var i = 0; i < frame.gestures.length; i++) {
var gesture = frame.gestures[i];
switch (gesture.type) {
case "circle":
gestureString += "<br>ID: " + gesture.id + "<br>type: " + gesture.type + ", "
+ "<br>center: " + vectorToString(gesture.center) + " mm, "
+ "<br>normal: " + vectorToString(gesture.normal, 2) + ", "
+ "<br>radius: " + gesture.radius.toFixed(1) + " mm, "
+ "<br>progress: " + gesture.progress.toFixed(2) + " rotations"
+ "<br>";
url = "http://192.168.130.234:5050/layerApi.aspx?cmd=move&move=Play";
break;
case "swipe":
//Classify swipe as either horizontal or vertical
var isHorizontal = Math.abs(gesture.direction[0]) > Math.abs(gesture.direction[1]);
//Classify as right-left or up-down
if(isHorizontal){
if (Math.abs(gesture.direction[0]) > Math.abs(gesture.direction[2])){
if(gesture.direction[0] > 0){
swipeDirection = "Right";
} else {
swipeDirection = "Left";
}
} else {
if(Math.abs(gesture.direction[2].toFixed(2)) > 0.5){
swipeDirection = "Play";
}
}
} else { //vertical
if (Math.abs(gesture.direction[1]) > Math.abs(gesture.direction[2])){
if(gesture.direction[1] > 0){
swipeDirection = "Up";
} else {
swipeDirection = "Down";
}
} else {
if(Math.abs(gesture.direction[2].toFixed(2)) > 0.5){
swipeDirection = "Play";
}
}
}
url = "http://192.168.130.234:5050/layerApi.aspx?cmd=move&move=" + swipeDirection;
gestureString += "<br>ID: " + gesture.id + "<br>type: " + gesture.type + ", "
+ "<br>direction " + swipeDirection
+ "<br>url " + url
+ "<br>gesture.direction vector: " + vectorToString(gesture.direction, 2) + ", "
+ "<br>";
break;
}
}
}
gestureOutput.innerHTML = gestureString + gestureOutput.innerHTML;
PlayShow();
})
var notStarted = true;
function vectorToString(vector, digits) {
if (typeof digits === "undefined") {
digits = 1;
}
return "(" + vector[0].toFixed(digits) + ", "
+ vector[1].toFixed(digits) + ", "
+ vector[2].toFixed(digits) + ")";
}
function PlayShow () {
var xhReq = new XMLHttpRequest();
//The "false" puts XMLHttpRequest in synchronous mode, and the code following will wait for a response before executing.
xhReq.open("GET", url, false); //(If these are really on the same domain, you might need to make this a relative call rather than an absolute one for it to work, not sure)
xhReq.send(null);
//put the response into reqResult
var reqResult = xhReq.responseText;
//check that the call was successful
if (reqResult=="<Status>Success</Status>") { //may want to change to a "contains" compare rather than an "equals"
showRunning = true;
}
else {
showRunning = false;
}
// result is now in reqResult
if (showRunning){
showText.innerHTML="Running Show";
} else
showText.innerHTML="Error! Try Again?";
notStarted=true;
}
</script>
I'm having some problems regarding a jQuery modal window. I'm a dba and SQL programmer and my goal is to build up a query which dynamically builds an HTML which contains a flash which links to a modal window that has another flash in it. Well the query is done and works flawlessly. However, I tried it on Internet Explorer and (unlike firefox and chrome) when you want to close the modal window it closes the whole browser window (with a warning message that says "beware, the browser's trying to close this tab etc").
I used an already existing jquery modal window code and styling (I believe that both matter). The problem is, that the whole query is done and if I change the whole jquery modal window, I'll have to change the query's logic, and drastically (believe me, I've checked).
So, my fastest solution would be to correct the jQuery code that is messing up the whole close thing (changing the sql stored proc would take a LOT of work). This is because the original example I used as a reference had this problem (I just didn't notice, due to jQuery supposively being a cross-browser solution for everything). You will see that it works flawlessly on FF and Chrome but not in IE
Here's the link: http://www.mediafire.com/?mcz70n870qmjch9
Thanks a lot!!!
Just in case I'm posting the code here as well:
/// <reference path="jquery-1.3.2.min-vsdoc.js" />
/************************************************************************************************************
* SIMPLE MODAL v 2.0
* © 2009 FISHBOWL MEDIA LLC
* http://fishbowlmedia.com
***********************************************************************************************************/
(function ($) {
/**********************************
* CUSTOMIZE THE DEFAULT SETTINGS
* Ex:
* var _settings = {
* id: 'modal',
* src: function(sender){
* return jQuery(sender).attr('href');
* },
* width: 800,
* height: 600
* }
**********************************/
var _settings = {
width: 800, // Use this value if not set in CSS or HTML
height: 600, // Use this value if not set in CSS or HTML
overlayOpacity: .85, // Use this value if not set in CSS or HTML
id: 'modal',
src: function (sender) {
return jQuery(sender).attr('href');
},
fadeInSpeed: 0,
fadeOutSpeed: 0
}
/**********************************
* DO NOT CUSTOMIZE BELOW THIS LINE
**********************************/
$.modal = function (options) {
return _modal(this, options);
}
$.modal.open = function () {
_modal.open();
}
$.modal.close = function () {
_modal.close();
}
$.fn.modal = function (options) {
return _modal(this, options);
}
_modal = function (sender, params) {
this.options = {
parent: null,
overlayOpacity: null,
id: null,
content: null,
width: null,
height: null,
modalClassName: null,
imageClassName: null,
closeClassName: null,
overlayClassName: null,
src: null
}
this.options = $.extend({}, options, _defaults);
this.options = $.extend({}, options, _settings);
this.options = $.extend({}, options, params);
this.close = function () {
jQuery('.' + options.modalClassName + ', .' + options.overlayClassName).fadeOut(_settings.fadeOutSpeed, function () { jQuery(this).unbind().remove(); });
}
this.open = function () {
if (typeof options.src == 'function') {
options.src = options.src(sender)
} else {
options.src = options.src || _defaults.src(sender);
}
var fileExt = /^.+\.((jpg)|(gif)|(jpeg)|(png)|(jpg))$/i;
var contentHTML = '';
if (fileExt.test(options.src)) {
contentHTML = '<div class="' + options.imageClassName + '"><img src="' + options.src + '"/></div>';
} else {
contentHTML = '<iframe width="' + options.width + '" height="' + options.height + '" frameborder="0" scrolling="no" allowtransparency="true" src="' + options.src + '"></iframe>';
}
options.content = options.content || contentHTML;
if (jQuery('.' + options.modalClassName).length && jQuery('.' + options.overlayClassName).length) {
jQuery('.' + options.modalClassName).html(options.content);
} else {
$overlay = jQuery((_isIE6()) ? '<iframe src="BLOCKED SCRIPT\'<html></html>\';" scrolling="no" frameborder="0" class="' + options.overlayClassName + '"></iframe><div class="' + options.overlayClassName + '"></div>' : '<div class="' + options.overlayClassName + '"></div>');
$overlay.hide().appendTo(options.parent);
$modal = jQuery('<div id="' + options.id + '" class="' + options.modalClassName + '" style="width:' + options.width + 'px; height:' + options.height + 'px; margin-top:-' + (options.height / 2) + 'px; margin-left:-' + (options.width / 2) + 'px;">' + options.content + '</div>');
$modal.hide().appendTo(options.parent);
$close = jQuery('<a class="' + options.closeClassName + '"></a>');
$close.appendTo($modal);
var overlayOpacity = _getOpacity($overlay.not('iframe')) || options.overlayOpacity;
$overlay.fadeTo(0, 0).show().not('iframe').fadeTo(_settings.fadeInSpeed, overlayOpacity);
$modal.fadeIn(_settings.fadeInSpeed);
$close.click(function () { jQuery.modal().close(); });
$overlay.click(function () { jQuery.modal().close(); });
}
}
return this;
}
_isIE6 = function () {
if (document.all && document.getElementById) {
if (document.compatMode && !window.XMLHttpRequest) {
return true;
}
}
return false;
}
_getOpacity = function (sender) {
$sender = jQuery(sender);
opacity = $sender.css('opacity');
filter = $sender.css('filter');
if (filter.indexOf("opacity=") >= 0) {
return parseFloat(filter.match(/opacity=([^)]*)/)[1]) / 100;
}
else if (opacity != '') {
return opacity;
}
return '';
}
_defaults = {
parent: 'body',
overlayOpacity: 85,
id: 'modal',
content: null,
width: 800,
height: 600,
modalClassName: 'modal-window',
imageClassName: 'modal-image',
closeClassName: 'close-window',
overlayClassName: 'modal-overlay',
src: function (sender) {
return jQuery(sender).attr('href');
}
}
})(jQuery);
And the style:
.modal-overlay {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
height: 100%;
width: 100%;
margin: 0;
padding: 0;
background: #131313;
opacity: .85;
filter: alpha(opacity=85);
z-index: 101;
}
.modal-window {
position: fixed;
top: 50%;
left: 50%;
margin: 0;
padding: 0;
z-index: 102;
background: #fff;
border: solid 8px #000;
-moz-border-radius: 8px;
-webkit-border-radius: 8px;
}
.close-window {
position: absolute;
width: 47px;
height: 47px;
right: -23px;
top: -23px;
background: transparent url(../images/close-button.png) no-repeat scroll right top;
text-indent: -99999px;
overflow: hidden;
cursor: pointer;
}
Thanks a ton in advance everyone =-)
EDIT: Daniele suggested that the problem might be on this line:
jQuery('.' + options.modalClassName + ', .' + options.overlayClassName).fadeOut(_settings.fadeOutSpeed, function () { jQuery(this).unbind().remove(); });
I did what he suggested and the result was this: It still doesn't work at all on IE (meaning that it still asks to close the whole window and not just the modal), and correctly shows and closes a first modal in FF and chrome, but after closing the first one its not able to correctly show another one.
Replace close() method of modal with closeModal or something similar:
$.modal.closeModal = function () {
_modal.closeModal();
}
[...]
this.closeModal = function () {
jQuery('.' + options.modalClassName + ', .' + options.overlayClassName).fadeOut(_settings.fadeOutSpeed, function () { jQuery(this).unbind().remove(); });
}
[...]
$close.click(function () { jQuery.modal().closeModal(); });
$overlay.click(function () { jQuery.modal().closeModal(); });
for me it works...