JS script runs partially on heroku but fully locally (Django) - javascript

document.addEventListener('DOMContentLoaded', function () {
// get button by id
// document.getElementById('closedjs_$').style.display='none';
var trips = document.querySelectorAll('*[id^="closedjs"]');
// trips = document.querySelectorAll('.closedjs')
trips.forEach((element) => {
element.style.display = 'none';
});
// checking if current passengers >= max passengers so changing Join btn to Closed
/*document.querySelectorAll('.joinleave').forEach((element) => {
var route_id = element.dataset.id;
var no_pass = parseFloat(document.querySelector(`#thepassengercounter_${route_id}`).innerHTML);
var max_pass = parseFloat(document.querySelector(`#max_pass_${route_id}`).innerHTML);
if (no_pass == max_pass) {
if (element.innerHTML = "Join") {
element.style.color = "#B22222";
element.style.border = "1px solid #B22222";
element.title = "Closed";
element.innerHTML = "Closed";
} else {
element.title = "Leave";
element.innerHTML = "Leave";
}
}
});*/
// so as to not reload the page after joining or leaving a trip. It updates the innerHTML instantly
//and then fetches as POST the route_id json page so as to update the DB
document.querySelectorAll('.joinleave').forEach((element) => {
element.onclick = () => {
var route_id = element.dataset.id;
fetch(`/route/${route_id}`)
.then((response) => response.json())
.then((route) => {
if (route.error) {
console.log(route.error);
alert(route.error);
}
var no_pass = parseFloat(
document.querySelector(`#thepassengercounter_${route_id}`).innerHTML
);
var max_pass = route['no_pass'];
var dist = route['dist'];
var key_num = route['key_num'];
var co2 = dist * 2.4 * 2;
var fin = document.querySelector(`#fin_${route_id}`).innerHTML;
var diff_p = max_pass - no_pass;
//console.log(route_id);
console.log('max passengers ', max_pass);
console.log('current passengers ', no_pass);
console.log('is date or time passed? ', fin);
console.log('diff pass ', diff_p);
alert('presssed');
//CODE EXECUTES UP TO HERE THE ALERT 'PRESSED' IS DISLAYED//
//console.log(dist)
//console.log(key_num)
// checking if current passengers >= max passengers so not allowing joinining but only leaving
if (no_pass < max_pass) {
if (diff_p == 1) {
if (element.title == 'Join') {
element.style.color = '#B22222';
element.style.border = '1px solid #B22222';
element.title = 'Leave';
element.innerHTML = 'Leave';
document.querySelector(`#thepassengercounter_${route_id}`)
.innerHTML++;
document.querySelector(`#closedjs_${route_id}`).style.display =
'block';
alert(
'Congrats you just saved ' +
co2.toFixed(2) +
' kg of CO2 by Carpooling'
);
join_route(route_id);
est_cost(route_id);
}
} else if (element.title == 'Leave') {
console.log(element);
element.title = 'Join';
element.innerHTML = 'Join';
element.style.color = '#228B22';
element.style.border = '1px solid #228B22';
document.querySelector(`#thepassengercounter_${route_id}`)
.innerHTML--;
leave_route(route_id);
est_cost(route_id);
}
} else if (no_pass == max_pass) {
if (fin === 'False') {
if (element.title == 'Leave') {
//console.log(element);
element.title = 'Join';
element.innerHTML = 'Join';
element.style.color = '#228B22';
element.style.border = '1px solid #228B22';
document.querySelector(`#thepassengercounter_${route_id}`)
.innerHTML--;
leave_route(route_id);
est_cost(route_id);
document.querySelector(`#closedjs_${route_id}`).style.display =
'none';
document.querySelector(`#closed_${route_id}`).style.display =
'none';
}
}
/* else {
if(element.title == "Closed")
{
alert('Sorry, max number of passengers reached');
element.style.color = "#B22222";
element.style.border = "1px solid #B22222";
element.title="Closed";
element.innerHTML="Closed";
//document.querySelector(`#thepassengercounter_${route_id}`).innerHTML++;
//join_route(route_id);
//est_cost(route_id);
}*/
/* else if (element.title == "Leave"){
console.log(element);
element.title="Join";
element.innerHTML="Join";
element.style.color = "#228B22";
element.style.border = "1px solid #228B22";
document.querySelector(`#thepassengercounter_${route_id}`).innerHTML--;
leave_route(route_id);
est_cost(route_id);
}*/
}
});
};
});
});
/* function sort() {
alert('sorting');
document.querySelectorAll('.media').forEach((element) => {
var route_id = element.dataset.id;
var fin = element.dataset.fin;
var fin_set = element.dataset.fin_set;
console.log(
route_id,
'style',
document.querySelector('.media').style.display
);
console.log(route_id, 'fin', fin);
console.log(route_id, 'fin_set', fin_set);
if (fin == 'True' || fin_set == 'True') {
document.querySelector('.media').style.display = 'none';
} else {
document.querySelector('.media').style.display = 'block';
}
});
} */
function join_route(route_id) {
fetch(`/join/route/${route_id}`, {
method: 'POST',
})
.then((response) => response.json())
.then((data) => console.log(data));
}
function leave_route(route_id) {
fetch(`/leave/route/${route_id}`, {
method: 'POST',
})
.then((response) => response.json())
.then((data) => console.log(data));
}
// Calculating the cost per passenger depending on the number of passengers instantly on the page (changing innerHTML)
// The updating of the DB is being done in models by the cost method separately
function est_cost(route_id) {
fetch(`/route/${route_id}`)
.then((response) => response.json())
.then((route) => {
if (route.error) {
console.log(route.error);
alert(route.error);
}
var origin = route['origin'];
var destination = route['destination'];
var init_cost = route['cost'];
var max_pass = route['no_pass'];
//console.log('the max passengers are', max_pass);
//console.log(init_cost);
var no_passengers = parseFloat(
document.querySelector(`#thepassengercounter_${route_id}`).innerHTML
);
//console.log(no_passengers);
if (no_passengers === 0) {
var cost = init_cost;
document.querySelector(`#costpp_${route_id}`).innerHTML = cost + '$';
} else {
var cost = init_cost / no_passengers;
document.querySelector(`#costpp_${route_id}`).innerHTML = cost + '$';
}
});
}
Code executes up to the point that PRESSED alert is displayed.
It doesn't execute the fetch nor the alert("Congrats you just saved "+(co2.toFixed(2))+' kg of CO2 by Carpooling').
No errors in console.
I can't understand how it can execute partially since it runs on the front end which means it has to do with the browser
Locally it runs smoothly.
What could be the prob?
It's a Django app.

Related

Memory game with javascript

I have a small problem that could ruin the game. Once you click a card you need to search for the other card with the same picture right? but the problem is you can also double click and it will think you found the other card. Anyone know how o solf this problem?
const cards = document.querySelectorAll(".cards .card");
cards.forEach((card) => {
card.addEventListener("click", () => {
card.classList.add("clicked");
if (counter === 0) {
firstSelection = card.getAttribute("meme");
counter++;
} else {
secondSelection = card.getAttribute("meme");
counter = 0;
if (firstSelection === secondSelection) {
const correctCards = document.querySelectorAll(".card[meme='" + firstSelection + "']");
score.innerHTML = parseInt(score.innerHTML) + 1
if (score.innerHTML >= 8)
correctCards[0].classList.add("checked");
correctCards[0].classList.remove("clicked");
correctCards[1].classList.add("checked");
correctCards[1].classList.remove("clicked");
} else {
const incorrectCards = document.querySelectorAll(".card.clicked");
incorrectCards[0].classList.add("red");
incorrectCards[1].classList.add("red");
setTimeout(() => {
incorrectCards[0].classList.remove("red");
incorrectCards[0].classList.remove("clicked");
incorrectCards[1].classList.remove("red");
incorrectCards[1].classList.remove("clicked");
}, 600);
}
}
});
});
You can set 2 global vars firstClickedCard and secondClickedCard, and on click, assign the card element (event.currentTarget) to these variables. Then on second click, check if (secondClickedCard === firstClickedCard) before any of your other logic, and reject the click event if this is true.
This should verify if the actual clicked element (not just the meme attribute) are the same or not.
Note: this is untested, and would be easier to verify if your question included a minimal, reproducible example.
const cards = document.querySelectorAll(".cards .card");
var firstClickedCard;
var secondClickedCard;
cards.forEach((card) => {
card.addEventListener("click", (e) => {
card.classList.add("clicked");
if (counter === 0) {
firstClickedCard = e.currentTarget;
firstSelection = card.getAttribute("meme");
counter++;
} else {
secondClickedCard = e.currentTarget;
// reject this click
if (secondClickedCard === firstClickedCard) {
secondClickedCard = null;
return false;
}
secondSelection = card.getAttribute("meme");
counter = 0;
if (firstSelection === secondSelection) {
const correctCards = document.querySelectorAll(".card[meme='" + firstSelection + "']");
score.innerHTML = parseInt(score.innerHTML) + 1
if (score.innerHTML >= 8)
correctCards[0].classList.add("checked");
correctCards[0].classList.remove("clicked");
correctCards[1].classList.add("checked");
correctCards[1].classList.remove("clicked");
} else {
const incorrectCards = document.querySelectorAll(".card.clicked");
incorrectCards[0].classList.add("red");
incorrectCards[1].classList.add("red");
setTimeout(() => {
incorrectCards[0].classList.remove("red");
incorrectCards[0].classList.remove("clicked");
incorrectCards[1].classList.remove("red");
incorrectCards[1].classList.remove("clicked");
}, 600);
}
}
});
});
Although there is a double click event (dblclick), it is not supported by all browsers. The way around this is to test for double clicks within your click event handlers and use a timer function (to see if two clicks happened within a select amount of time). I use 300ms for the timer, but you may have to play around with that a bit.
const cards = document.querySelectorAll(".cards .card");
let clickCount = 0;
cards.forEach((card) => {
card.addEventListener("click", () => {
clickCount ++;
if (clickCount == 1) {
clickTimer = setTimeout(() => {
clickCount = 0;
//single click functionality here
card.classList.add("clicked");
if (counter === 0) {
firstSelection = card.getAttribute("meme");
counter++;
} else {
secondSelection = card.getAttribute("meme");
counter = 0;
if (firstSelection === secondSelection) {
const correctCards = document.querySelectorAll(".card[meme='" + firstSelection + "']");
score.innerHTML = parseInt(score.innerHTML) + 1
if (score.innerHTML >= 8)
correctCards[0].classList.add("checked");
correctCards[0].classList.remove("clicked");
correctCards[1].classList.add("checked");
correctCards[1].classList.remove("clicked");
} else {
const incorrectCards = document.querySelectorAll(".card.clicked");
incorrectCards[0].classList.add("red");
incorrectCards[1].classList.add("red");
setTimeout(() => {
incorrectCards[0].classList.remove("red");
incorrectCards[0].classList.remove("clicked");
incorrectCards[1].classList.remove("red");
incorrectCards[1].classList.remove("clicked");
}, 600);
}
}
}, 300);
} else if (clickCount == 2) {
clearTimeout(clickTimer);
clickCount = 0;
console.log("This was a double click!");
}
});
});

I want the whatsapp web bot to reply with an image pulled from a url how do I add the function?

The bot replies well when a command is sent.
How do I make the WhatsApp web bot to reply with an image pulled from a URL? I want it to be able to reply with an image pulled from a URL, for example, www.school.com/pic.jpg. On the code if a user text #time it replies with time and Date but I want it to reply with an image.
//
// FUNCTIONS
//
// Get random value between a range
function rand(high, low = 0) {
return Math.floor(Math.random() * (high - low + 1) + low);
}
function getElement(id, parent){
if (!elementConfig[id]){
return false;
}
var elem = !parent ? document.body : parent;
var elementArr = elementConfig[id];
for (var x in elementArr){
var pos = elementArr[x];
if (isNaN(pos*1)){ //dont know why, but for some reason after the last position it loops once again and "pos" is loaded with a function WTF. I got tired finding why and did this
continue;
}
if (!elem.childNodes[pos]){
return false;
}
elem = elem.childNodes[pos];
}
return elem;
}
function getLastMsg(){
var messages = document.querySelectorAll('.msg');
var pos = messages.length-1;
while (messages[pos] && (messages[pos].classList.contains('msg-system') || messages[pos].querySelector('.message-out'))){
pos--;
if (pos <= -1){
return false;
}
}
if (messages[pos] && messages[pos].querySelector('.selectable-text')){
return messages[pos].querySelector('.selectable-text').innerText;
} else {
return false;
}
}
function getUnreadChats(){
var unreadchats = [];
var chats = getElement("chats");
if (chats){
chats = chats.childNodes;
for (var i in chats){
if (!(chats[i] instanceof Element)){
continue;
}
var icons = getElement("chat_icons", chats[i]).childNodes;
if (!icons){
continue;
}
for (var j in icons){
if (icons[j] instanceof Element){
if (!(icons[j].childNodes[0].getAttribute('data-icon') == 'muted' || icons[j].childNodes[0].getAttribute('data-icon') == 'pinned')){
unreadchats.push(chats[i]);
break;
}
}
}
}
}
return unreadchats;
}
function didYouSendLastMsg(){
var messages = document.querySelectorAll('.msg');
if (messages.length <= 0){
return false;
}
var pos = messages.length-1;
while (messages[pos] && messages[pos].classList.contains('msg-system')){
pos--;
if (pos <= -1){
return -1;
}
}
if (messages[pos].querySelector('.message-out')){
return true;
}
return false;
}
// Call the main function again
const goAgain = (fn, sec) => {
// const chat = document.querySelector('div.chat:not(.unread)')
// selectChat(chat)
setTimeout(fn, sec * 1000)
}
// Dispath an event (of click, por instance)
const eventFire = (el, etype) => {
var evt = document.createEvent("MouseEvents");
evt.initMouseEvent(etype, true, true, window,0, 0, 0, 0, 0, false, false, false, false, 0, null);
el.dispatchEvent(evt);
}
// Select a chat to show the main box
const selectChat = (chat, cb) => {
const title = getElement("chat_title",chat).title;
eventFire(chat.firstChild.firstChild, 'mousedown');
if (!cb) return;
const loopFewTimes = () => {
setTimeout(() => {
const titleMain = getElement("selected_title").title;
if (titleMain !== undefined && titleMain != title){
console.log('not yet');
return loopFewTimes();
}
return cb();
}, 300);
}
loopFewTimes();
}
// Send a message
const sendMessage = (chat, message, cb) => {
//avoid duplicate sending
var title;
if (chat){
title = getElement("chat_title",chat).title;
} else {
title = getElement("selected_title").title;
}
ignoreLastMsg[title] = message;
messageBox = document.querySelectorAll("[contenteditable='true']")[0];
//add text into input field
messageBox.innerHTML = message.replace(/ /gm,'');
//Force refresh
event = document.createEvent("UIEvents");
event.initUIEvent("input", true, true, window, 1);
messageBox.dispatchEvent(event);
//Click at Send Button
eventFire(document.querySelector('span[data-icon="send"]'), 'click');
cb();
}
//
// MAIN LOGIC
//
const start = (_chats, cnt = 0) => {
// get next unread chat
const chats = _chats || getUnreadChats();
const chat = chats[cnt];
var processLastMsgOnChat = false;
var lastMsg;
if (!lastMessageOnChat){
if (false === (lastMessageOnChat = getLastMsg())){
lastMessageOnChat = true; //to prevent the first "if" to go true everytime
} else {
lastMsg = lastMessageOnChat;
}
} else if (lastMessageOnChat != getLastMsg() && getLastMsg() !== false && !didYouSendLastMsg()){
lastMessageOnChat = lastMsg = getLastMsg();
processLastMsgOnChat = true;
}
if (!processLastMsgOnChat && (chats.length == 0 || !chat)) {
console.log(new Date(), 'nothing to do now... (1)', chats.length, chat);
return goAgain(start, 3);
}
// get infos
var title;
if (!processLastMsgOnChat){
title = getElement("chat_title",chat).title + '';
lastMsg = (getElement("chat_lastmsg", chat) || { innerText: '' }).innerText; //.last-msg returns null when some user is typing a message to me
} else {
title = getElement("selected_title").title;
}
// avoid sending duplicate messaegs
if (ignoreLastMsg[title] && (ignoreLastMsg[title]) == lastMsg) {
console.log(new Date(), 'nothing to do now... (2)', title, lastMsg);
return goAgain(() => { start(chats, cnt + 1) }, 0.1);
}
// what to answer back?
let sendText
if (lastMsg.toUpperCase().indexOf('#HELP') > -1){
sendText = `
Cool ${title}! Some commands that you can send me:
1. *#TIME*
2. *#JOKE*`
}
if (lastMsg.toUpperCase().indexOf('#About') > -1){
sendText = `
Cool ${title}! Some commands that you can send me:
*${new Date()}*`
}
if (lastMsg.toUpperCase().indexOf('#TIME') > -1){
sendText = `
Don't you have a clock, dude?
*${new Date()}*`
}
if (lastMsg.toUpperCase().indexOf('#JOKE') > -1){
sendText = jokeList[rand(jokeList.length - 1)];
}
// that's sad, there's not to send back...
if (!sendText) {
ignoreLastMsg[title] = lastMsg;
console.log(new Date(), 'new message ignored -> ', title, lastMsg);
return goAgain(() => { start(chats, cnt + 1) }, 0.1);
}
console.log(new Date(), 'new message to process, uhull -> ', title, lastMsg);
// select chat and send message
if (!processLastMsgOnChat){
selectChat(chat, () => {
sendMessage(chat, sendText.trim(), () => {
goAgain(() => { start(chats, cnt + 1) }, 0.1);
});
})
} else {
sendMessage(null, sendText.trim(), () => {
goAgain(() => { start(chats, cnt + 1) }, 0.1);
});
}
}
start();

Progress bar not resetting

I'm creating a countdown of 10 seconds, and at the end, some functions triggers.
These functions that recall the countdown function to start again. However, when it's called again, the bar is still full, resulting in a loop.
Here's the countdown function.
function LoadTime() {
firebase.auth().onAuthStateChanged(User => {
if(User) {
var RemainTime = 10;
var DownTime = setInterval(function(){
document.getElementById("progressBar").value = 10 - --RemainTime;
if(RemainTime <= 0)
clearInterval(DownTime);
if (RemainTime == 0){
storewager();
if (Roulette.bet == 1) {
RouOutcome();
}
else {
LoadTime();
}
}
},1000);
} else {
alert("please login");
}
});
}
I want this functions to reset the progress bar each time it's triggered. Been stuck on this for a while, so any help is much appreciated.
EDIT:
Here's the tree of the functions.
Page load --> LoadTime --> (end of countdown) --> (Outcome process) --> RouOutcome() --> LoadTime().
Seems to be when LoadTime is triggered when it's already finished once, it seems to run the process multiple times. It may be to do with the alert boxes causing issues for the countdown.
Been stuck on this for hours, so any help is much appreciated.
EDIT 2:
Here's are the relevant functions in the correct order. This is assuming the users picks a bet option, and enters a bet. I'm trying to create roulette. Is it possible that the issue could be with the alerts?
function LoadTime() {
Roulette.load = 1;
CoinFlip.load = 0;
document.getElementById().style.visibility = "hidden";
firebase.auth().onAuthStateChanged(User => {
if(User) {
console.log("user is logged in");
Roulette.choice = 0;
var RemainTime = 15;
var DownTime = setInterval(function(){
document.getElementById("progressBar").value = 15 - --RemainTime;
if(RemainTime <= 0)
clearInterval(DownTime);
if (RemainTime == 0){
storewager();
if (Roulette.bet == 1) {
RouOutcome();
}
else {
LoadTime();
}
}
},1000);
} else {
alert("please login");
}
});
}
function storewager(){
var UserID = firebase.auth().currentUser.uid;
firebase.database().ref("Users").child(UserID).child("coinbet").set(0);
var coinwager = document.getElementById("coininput").value;
if (coinwager > 0) {
Roulette.bet = 1;
var balref = firebase.database().ref("Users").child(UserID).child("coinbet");
firebase.database().ref("Users").child(UserID).child("coinbet").set(coinwager);
var coinref = firebase.database().ref();
coinref.child("coinbet").set(coinwager);
BalVer();
}
else {
alert("No bet was placed");
Roulette.bet = 0;
LoadTime();
}
}
function BalVer(){
var UserID = firebase.auth().currentUser.uid;
var dbRoot = firebase.database().ref("Users").child(UserID);
dbRoot.once("value", snap => {
var cData = snap.val();
var cBet = cData.coinbet;
var uBal = cData.userbalance;
var BalUp = uBal-cBet;
if (BalUp < 0) {
alert("You do not have enough balance")
var BetWipe = firebase.database().ref("Users").child(UserID).child("coinbet").set(0);
}
else {
changeuserbal();
}
});
}
function changeuserbal(coinwager){
var UserID = firebase.auth().currentUser.uid;
var dbRoot = firebase.database().ref("Users").child(UserID);
dbRoot.once("value", snap => {
var cData = snap.val();
var cBet = cData.coinbet;
var uBal = cData.userbalance;
var BalUp = uBal-cBet;
firebase.database().ref("Users").child(UserID).child("userbalance").set(BalUp);
if (CoinFlip.load == 1) {
CoinOutcome();
}
else {
RouOutcome();
}
});
}
function RouOutcome(UserID) {
var OutCome = 0 + (Math.random() * 10000);
var UserID = firebase.auth().currentUser.uid;
if (OutCome <= 10000) {
if (Roulette.choice == 1) {
alert("You won");
var dbRoot = firebase.database().ref("Users").child(UserID);
dbRoot.once("value", snap => {
var cData = snap.val();
var cBet = cData.coinbet;
var uBal = cData.userbalance;
var WinBal = cBet * 2 + uBal
var NewBal = firebase.database().ref("Users").child(UserID).child("userbalance").set(WinBal);
//UpdateBal();
Roulette.comp = 1;
LoadTime();
});
}
else {
alert("you lost/didn't place bet");
Roulette.comp = 1;
LoadTime();
}
}
else if ((OutCome >= 4738) && (OutCome <=9474)) {
var UserID = firebase.auth().currentUser.uid;
if (Roulette.choice == 2) {
alert("You won");
var dbRoot = firebase.database().ref("Users").child(UserID);
dbRoot.once("value", snap => {
var cData = snap.val();
var cBet = cData.coinbet;
var uBal = cData.userbalance;
var WinBal = cBet*2+uBal
var NewBal = firebase.database().ref("Users").child(UserID).child("userbalance").set(WinBal);
//UpdateBal();
LoadTime();
});
}
else {
alert("you lost/didn't place bet");
LoadTime();
}
}
else {
var UserID = firebase.auth().currentUser.uid;
if (Roulette.choice == 3) {
alert("You won");
var dbRoot = firebase.database().ref("Users").child(UserID);
dbRoot.once("value", snap => {
var cData = snap.val();
var cBet = cData.coinbet;
var uBal = cData.userbalance;
var WinBal = cBet*14+uBal
var NewBal = firebase.database().ref("Users").child(UserID).child("userbalance").set(WinBal);
//UpdateBal();
LoadTime();
});
}
else {
alert("you lost/didn't place bet");
LoadTime();
}
}
}
Thanks very much for your help, if you need any more info please say.
Here is an example I created for you to follow. You don't show you attempt at resetting the bar so this is the best I can do at explaining for now.
var pBar = document.getElementById("progressBar");
var pText = document.getElementById("progressText");
startTimer();
function startTimer() {
var downIncrement = 10;
var DownTime = setInterval(function() {
var currentValue = pBar.getAttribute("aria-valuenow");
var newValue = currentValue - downIncrement;
pBar.setAttribute("aria-valuenow", newValue);
pBar.style = "width:" + newValue + "%";
pText.textContent = newValue / 10;
if (newValue <= 0) {
console.log("time is up!");
clearInterval(DownTime);
var Roulette = storewager();
if (Roulette.bet == 1) {
RouOutcome();
} else {
LoadTime();
}
}
},
1000);
}
function storewager() {
console.log("done with store wager");
return {
bet: 1
};
}
function RouOutcome() {
console.log("done with RouOutcome");
// restart progress bar
LoadTime();
}
function LoadTime() {
pBar.setAttribute("aria-valuenow", 100);
pBar.style = "width: 100%";
pText.textContent = "10";
}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<div class="progress">
<div id="progressBar" class="progress-bar" role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" style="width:100%">
<span id="progressText">10</span>
</div>
</div>

JavaScript - Set function to return all items based on 1 or 2 selected tags (NO jQUERY)

I have some JavaScrip that is meant to check if there are any media tags selected or industry tags selected--this is so the portfolio items can be sorted and displayed accordingly in the browser.
What I have almost works 100%, but I can't figure out how to make it so that if only a media tag is selected or if only an industry tag is selected, the portfolio items should still be sorted accordingly. Currently, you have to select a media tag AND an industry tag, but I'd like users to be able to search using just a media tag OR just an industry tag.
Here is what I want to accomplish: If only a media tag is selected, then get all portfolio pieces that are associated with that media tag. If only an industry tag is selected, get all portfolio items that are associated with that industry tag. If a media tag AND industry tag are selected at the same time, get all portfolio items that are associated with BOTH.
Vanilla JS isn't my strong point so forgive me if this is a dumb question, but this has had me stumped for hours now.
No jQuery answers, please, as this whole page's functionality is built using JavaScript.
Here is the function:
var update = function () {
closeDrawer();
// update ui to reflect tag changes
// get our list of items to display
var itemsToDisplay = [];
var currentMediaTag = controlsContainer.querySelector('.media.selected');
var currentIndustryTag = controlsContainer.querySelector('.industry.selected');
if (currentMediaTag != "" && currentMediaTag != null) {
selectedMediaFilter = currentMediaTag.innerHTML;
}
if (currentIndustryTag != "" && currentIndustryTag != null) {
selectedIndustryFilter = currentIndustryTag.innerHTML;
}
if (selectedMediaFilter == "" && selectedIndustryFilter == "") {
itemsToDisplay = portfolioItems.filter(function (item) {
return item.preferred;
});
} else {
itemsToDisplay = portfolioItems.filter(function (item) {
var mediaTags = item.media_tags,
industryTags = item.industry_tags;
if(industryTags.indexOf(selectedIndustryFilter) < 0){
return false;
}
else if(mediaTags.indexOf(selectedMediaFilter) < 0){
return false;
}
else{
return true;
}
});
}
renderItems(itemsToDisplay);
}
Not entirely sure it's necessary but just in case, here is the complete JS file that handles the portfolio page:
(function ($) {
document.addEventListener("DOMContentLoaded", function (event) {
// for portfolio interaction
var portfolioGrid = (function () {
var gridSize = undefined,
parentContainer = document.querySelector('.portfolio-item-container');
containers = parentContainer.querySelectorAll('.view'),
drawer = parentContainer.querySelector('.drawer'),
bannerContainer = drawer.querySelector('.banner-container'),
thumbsContainer = drawer.querySelector('.thumbs-container'),
descriptionContainer = drawer.querySelector('.client-description'),
clientNameContainer = drawer.querySelector('.client-name'),
controlsContainer = document.querySelector('.portfolio-controls-container'),
selectedMediaFilter = "", selectedIndustryFilter = "";
var setGridSize = function () {
var windowSize = window.innerWidth,
previousGridSize = gridSize;
if (windowSize > 1800) {
gridSize = 5;
} else if (windowSize > 900) {
gridSize = 4;
} else if (windowSize > 600 && windowSize <= 900) {
gridSize = 3;
} else {
gridSize = 2;
}
if (previousGridSize != gridSize) {
closeDrawer();
}
};
var attachResize = function () {
window.onresize = function () {
setGridSize();
};
};
var getRowClicked = function (boxNumber) {
return Math.ceil(boxNumber / gridSize);
};
var getLeftSibling = function (row) {
var cI = row * gridSize;
return containers[cI >= containers.length ? containers.length - 1 : cI];
};
var openDrawer = function () {
drawer.className = 'drawer';
scrollToBanner();
};
var scrollToBanner = function () {
var mainContainer = document.querySelector('#main-container'),
mainBounding = mainContainer.getBoundingClientRect(),
scrollY = (drawer.offsetTop - mainBounding.bottom) - 10,
currentTop = document.body.getBoundingClientRect().top;
animate(document.body, "scrollTop", "", document.body.scrollTop, scrollY, 200, true);
};
var animate = function (elem, style, unit, from, to, time, prop) {
if (!elem) return;
var start = new Date().getTime(),
timer = setInterval(function () {
var step = Math.min(1, (new Date().getTime() - start) / time);
if (prop) {
elem[style] = (from + step * (to - from)) + unit;
} else {
elem.style[style] = (from + step * (to - from)) + unit;
}
if (step == 1) clearInterval(timer);
}, 25);
elem.style[style] = from + unit;
}
var closeDrawer = function () {
drawer.className = 'drawer hidden';
};
var cleanDrawer = function () {
bannerContainer.innerHTML = "";
clientNameContainer.innerHTML = "";
descriptionContainer.innerHTML = "";
thumbsContainer.innerHTML = "";
};
var resetThumbs = function () {
Array.prototype.forEach.call(thumbsContainer.querySelectorAll('.thumb'), function (t) {
t.className = "thumb";
});
};
var handleBannerItem = function (item) {
bannerContainer.innerHTML = "";
if (item.youtube) {
var videoContainer = document.createElement('div'),
iframe = document.createElement('iframe');
videoContainer.className = "videowrapper";
iframe.className = "youtube-video";
iframe.src = "https://youtube.com/embed/" + item.youtube;
videoContainer.appendChild(iframe);
bannerContainer.appendChild(videoContainer);
} else if (item.soundcloud) {
var iframe = document.createElement('iframe');
iframe.src = item.soundcloud;
iframe.className = "soundcloud-embed";
bannerContainer.appendChild(iframe);
} else if (item.banner) {
var bannerImage = document.createElement('img');
bannerImage.src = item.banner;
bannerContainer.appendChild(bannerImage);
}
};
var attachClick = function () {
Array.prototype.forEach.call(containers, function (n, i) {
n.querySelector('a.info').addEventListener('click', function (e) {
e.preventDefault();
});
n.addEventListener('click', function (e) {
var boxNumber = i + 1,
row = getRowClicked(boxNumber);
var containerIndex = row * gridSize;
if (containerIndex >= containers.length) {
// we're inserting drawer at the end
parentContainer.appendChild(drawer);
} else {
// we're inserting drawer in the middle somewhere
var leftSiblingNode = getLeftSibling(row);
leftSiblingNode.parentNode.insertBefore(drawer, leftSiblingNode);
}
// populate
cleanDrawer();
var mediaFilterSelected = document.querySelector('.media-tags .tag-container .selected');
var selectedFilters = "";
if (mediaFilterSelected != "" && mediaFilterSelected != null) {
selectedFilters = mediaFilterSelected.innerHTML;
}
var portfolioItemName = '';
var selectedID = this.getAttribute('data-portfolio-item-id');
var data = portfolioItems.filter(function (item) {
portfolioItemName = item.name;
return item.id === selectedID;
})[0];
clientNameContainer.innerHTML = data.name;
descriptionContainer.innerHTML = data.description;
var childItems = data.child_items;
//We will group the child items by media tag and target the unique instance from each group to get the right main banner
Array.prototype.groupBy = function (prop) {
return this.reduce(function (groups, item) {
var val = item[prop];
groups[val] = groups[val] || [];
groups[val].push(item);
return groups;
}, {});
}
var byTag = childItems.groupBy('media_tags');
if (childItems.length > 0) {
handleBannerItem(childItems[0]);
var byTagValues = Object.values(byTag);
byTagValues.forEach(function (tagValue) {
for (var t = 0; t < tagValue.length; t++) {
if (tagValue[t].media_tags == selectedFilters) {
handleBannerItem(tagValue[0]);
}
}
});
childItems.forEach(function (item, i) {
var img = document.createElement('img'),
container = document.createElement('div'),
label = document.createElement('p');
container.appendChild(img);
var mediaTags = item.media_tags;
container.className = "thumb";
label.className = "childLabelInactive thumbLbl";
thumbsContainer.appendChild(container);
if (selectedFilters.length > 0 && mediaTags.length > 0) {
for (var x = 0; x < mediaTags.length; x++) {
if (mediaTags[x] == selectedFilters) {
container.className = "thumb active";
label.className = "childLabel thumbLbl";
}
}
}
else {
container.className = i == 0 ? "thumb active" : "thumb";
}
img.src = item.thumb;
if (item.media_tags != 0 && item.media_tags != null) {
childMediaTags = item.media_tags;
childMediaTags.forEach(function (cMTag) {
varLabelTxt = document.createTextNode(cMTag);
container.appendChild(label);
label.appendChild(varLabelTxt);
});
}
img.addEventListener('click', function (e) {
scrollToBanner();
resetThumbs();
handleBannerItem(item);
container.className = "thumb active";
});
});
}
openDrawer();
});
});
};
var preloadImages = function () {
portfolioItems.forEach(function (item) {
var childItems = item.child_items;
childItems.forEach(function (child) {
(new Image()).src = child.banner;
(new Image()).src = child.thumb;
});
});
};
//////////////////////////////////// UPDATE FUNCTION /////////////////////////////////////
var update = function () {
closeDrawer();
// update ui to reflect tag changes
// get our list of items to display
var itemsToDisplay = [];
var currentMediaTag = controlsContainer.querySelector('.media.selected');
var currentIndustryTag = controlsContainer.querySelector('.industry.selected');
if (currentMediaTag != "" && currentMediaTag != null) {
selectedMediaFilter = currentMediaTag.innerHTML;
}
if (currentIndustryTag != "" && currentIndustryTag != null) {
selectedIndustryFilter = currentIndustryTag.innerHTML;
}
if (selectedMediaFilter == "" && selectedIndustryFilter == "") {
itemsToDisplay = portfolioItems.filter(function (item) {
return item.preferred;
});
} else {
itemsToDisplay = portfolioItems.filter(function (item) {
var mediaTags = item.media_tags,
industryTags = item.industry_tags;
if (industryTags.indexOf(selectedIndustryFilter) < 0) {
return false;
}
else if (mediaTags.indexOf(selectedMediaFilter) < 0) {
return false;
}
else {
return true;
}
});
}
renderItems(itemsToDisplay);
}
//////////////////////////////////// RENDERITEMS FUNCTION /////////////////////////////////////
var renderItems = function (items) {
var children = parentContainer.querySelectorAll('.view');
Array.prototype.forEach.call(children, function (child) {
// remove all event listeners then remove child
parentContainer.removeChild(child);
});
items.forEach(function (item) {
var container = document.createElement('div'),
thumb = document.createElement('img'),
mask = document.createElement('div'),
title = document.createElement('h6'),
excerpt = document.createElement('p'),
link = document.createElement('a');
container.className = "view view-tenth";
container.setAttribute('data-portfolio-item-id', item.id);
thumb.src = item.thumb;
mask.className = "mask";
title.innerHTML = item.name;
excerpt.innerHTML = item.excerpt;
link.href = "#";
link.className = "info";
link.innerHTML = "View Work";
container.appendChild(thumb);
container.appendChild(mask);
mask.appendChild(title);
mask.appendChild(excerpt);
mask.appendChild(link);
parentContainer.insertBefore(container, drawer);
});
containers = parentContainer.querySelectorAll('.view');
attachClick();
};
var filterHandler = function (linkNode, tagType) {
var prevSelection = document.querySelector("." + tagType + '.selected');
if (prevSelection != "" && prevSelection != null) {
prevSelection.className = tagType + ' tag';
}
linkNode.className = tagType + ' tag selected';
update();
};
var clearFilters = function (nodeList, filterType) {
Array.prototype.forEach.call(nodeList, function (node) {
node.className = filterType + " tag";
console.log("Clear filters function called");
});
}
var attachFilters = function () {
var mediaFilters = controlsContainer.querySelectorAll('.tag.media'),
industryFilters = controlsContainer.querySelectorAll('.tag.industry'),
filterToggle = controlsContainer.querySelectorAll('.filter-toggle');
// resets
controlsContainer.querySelector('.media-tags .reset')
.addEventListener('click',
function (e) {
e.preventDefault();
selectedMediaFilter = "";
clearFilters(controlsContainer.querySelectorAll('.media-tags a.tag'), "media");
update();
}
);
controlsContainer.querySelector('.industry-tags .reset')
.addEventListener('click',
function (e) {
e.preventDefault();
selectedIndustryFilter = "";
clearFilters(controlsContainer.querySelectorAll('.industry-tags a.tag'), "industry");
update();
}
);
Array.prototype.forEach.call(filterToggle, function (toggle) {
toggle.addEventListener('click', function (e) {
if (controlsContainer.className.indexOf('open') < 0) {
controlsContainer.className += ' open';
} else {
controlsContainer.className = controlsContainer.className.replace('open', '');
}
});
});
//Attaches a click event to each media tag "button"
Array.prototype.forEach.call(mediaFilters, function (filter) {
filter.addEventListener('click', function (e) {
e.preventDefault();
// var selectedMediaFilter = controlsContainer.querySelector('.media.selected');
//console.log("Media tag: " +this.innerHTML); *THIS WORKS*
filterHandler(this, "media");
});
});
Array.prototype.forEach.call(industryFilters, function (filter) {
filter.addEventListener('click', function (e) {
e.preventDefault();
// var selectedIndustryFilter = this.querySelector('.industry.selected');
// console.log("Industry tag: " +this.innerHTML); *THIS WORKS*
filterHandler(this, "industry");
});
});
};
return {
init: function () {
setGridSize();
attachResize();
attachClick();
preloadImages();
// portfolio page
if (controlsContainer) {
attachFilters();
}
}
};
})();
portfolioGrid.init();
});
}());
$ = jQuery.noConflict();
if(industryTags.indexOf(selectedIndustryFilter) < 0){
return false;
}
else if(mediaTags.indexOf(selectedMediaFilter) < 0){
return false;
}
That part is giving you headaches. Whenever no industry tag or media tag is selected this will exit the function.
Change to:
if(industryTags.indexOf(selectedIndustryFilter) < 0 && mediaTags.indexOf(selectedMediaFilter) < 0){
return false;
}
Now it will test if at least one tag is selected. If so then render items.
I made a change just to experiment with an idea, and this setup works:
if((selectedIndustryFilter !="" && industryTags.indexOf(selectedIndustryFilter) < 0) || (selectedMediaFilter !="" && mediaTags.indexOf(selectedMediaFilter) < 0)){
return false;
}
return true;
Not sure if it's the best solution ever but it seems to work and I'm not going to complain.

Nativescript location runtime updates

I'm new to Nativescript (used to be a Corona/Lua developer) and I need to create a function (similar to a RuntimeEventListener in Lua) that constantly gets user location and updates a dashboard with speed and altitude, for example.
My current code gets this info only when a button is pressed (which does not make sense for the kind of app I am trying to build). Question is, how to create and invoke such listener/function?
I am coding in Javascript and below it is my current code:
var Observable = require("data/observable").Observable;
var frames = require("ui/frame");
var orientation = require('nativescript-orientation');
orientation.enableRotation(); // The screen will rotate
console.log(orientation.getOrientation()); // Returns the enum DeviceOrientation value
var dialogs = require("ui/dialogs");
// Get geo coordinates
var geolocation = require("nativescript-geolocation");
if (!geolocation.isEnabled()) {
geolocation.enableLocationRequest();
}
/*
var watchID
watchId = geolocation.watchLocation(
function (loc) {
if (loc) {
console.log("(watchid) Received location: " + loc);
}
},
function(e){
console.log("(watchid) Error: " + e.message);
},
{desiredAccuracy: 3, updateDistance: 10, minimumUpdateTime : 1000 * 20}); // should update every 20 sec according to google documentation this is not so sure.
*/
//variables for the dashboard and the Origin
var originLoc //holds the lat,long of the starting point
var originHeading = "NNW"
var originTime = "0"
var originDistance = "0"
var mySpeed = "0"
var myDuration = "00:00"
var myDistance = "0"
var myAltitude = "0";
var myDirection;
var butAction = "START" //button action when it starts
var fbMeasurement = "imperial";
//Sets the right heading of the compass (if landscape, subtracts 90 degrees)
function headingCompass(args) {
var compassHead = "";
if (args>12 && args<=34) {
compassHead = "NNE";
} else if (args>34 && args<=57) {
compassHead = "NE";
} else if (args>57 && args<=80) {
compassHead = "ENE";
} else if (args>80 && args<=102) {
compassHead = "E";
} else if (args>102 && args<=124) {
compassHead = "ESE";
} else if (args>124 && args<=147) {
compassHead = "SE";
} else if (args>147 && args<=170) {
compassHead = "SSE";
} else if (args>170 && args<=192) {
compassHead = "S";
} else if (args>192 && args<=215) {
compassHead = "SSW";
} else if (args>215 && args<=237) {
compassHead = "SW";
} else if (args>237 && args<=260) {
compassHead = "WSW";
} else if (args>260 && args<=282) {
compassHead = "W";
} else if (args>282 && args<=305) {
compassHead = "WNW";
} else if (args>305 && args<=327) {
compassHead = "NW";
} else if (args>327 && args<=350) {
compassHead = "NNW";
} else {
compassHead = "N";
}
return compassHead;
}
//Gets current location when app starts
var geolocation = require("nativescript-geolocation");
if (!geolocation.isEnabled()) {
geolocation.enableLocationRequest();
}
var location = geolocation.getCurrentLocation({desiredAccuracy: 3, updateDistance: 10, maximumAge: 20000, timeout: 20000}).
then(function(loc) {
if (loc) {
console.log("Current location is: " + loc);
originLoc = loc;
if (fbMeasurement === "imperial") {
myAltitude = parseInt(loc.altitude * 3.28084);
mySpeed = (loc.speed * 2.23694).toFixed(1);
} else {
mySpeed = loc.speed.toFixed(1);
myAltitude = parseInt(loc.altitude);
}
myDirection = headingCompass(loc.direction)
}
}, function(e){
console.log("Error: " + e.message);
});
function createViewModel() {
var viewModel = new Observable();
viewModel.originHeading = originHeading;
viewModel.originTime = originTime;
viewModel.originDistance = originDistance;
viewModel.mySpeed = mySpeed;
viewModel.myDuration = myDuration;
viewModel.myDistance = myDistance;
viewModel.myAltitude = myAltitude;
viewModel.butAction = butAction;
//STARTs
var watchid;
viewModel.onTapStart = function(args) {
if (butAction==="START") {
//change button color to RED
var btn = args.object;
btn.backgroundColor = "#FF0000";
//change button text to "STOP"
this.set("butAction","STOP");
butAction = "STOP";
watchId = geolocation.watchLocation(
function (loc) {
if (loc) {
console.log("Received location: " + loc);
if (fbMeasurement === "imperial") {
myAltitude = parseInt(loc.altitude * 3.28084);
mySpeed = (loc.speed * 2.23694).toFixed(1);
} else {
mySpeed = loc.speed.toFixed(1);
myAltitude = parseInt(loc.altitude);
}
myDirection = headingCompass(loc.direction);
}
},
function(e){
console.log("Error: " + e.message);
},
{desiredAccuracy: 3, updateDistance: 10, minimumUpdateTime : 1000 * 1}); // should update every 20 sec according to google documentation this is not so sure.
} else {
//change button color to GREEN
var btn = args.object;
btn.backgroundColor = "#00FF00";
//change button text to "START"
this.set("butAction","START")
butAction = "START";
if (watchId) {
geolocation.clearWatch(watchId);
}
}
this.set("myAltitude",myAltitude);
this.set("mySpeed",mySpeed);
this.set("myDistance",myDirection);
}
return viewModel;
}
exports.createViewModel = createViewModel;
The watchlocation method is, in fact, a listener and will update your location when it is changed (based on this arguments). However, you will need to use some observable properties to update the info and reuse it where and when needed. Also, keep in mind that in Android the location is sometimes triggered after some distance (in my case approx. 100 steps gave the difference in the fourth sign after the dot).
If you are familiar with MVVM pattern this is the one used on regular basis in NativeScript applications.Here you can find the article for Data Binding in NativeScript.
So basically just execute your watch function (e.g. using loaded event for your Page) and then watch for changes in the Observable model (e.g. create Observable property latitude and use the updated info when and where needed)
e.g.
vm = new Observable();
vm.set("altitude", someDefaultValue);
vm.set("longitude", someDefaultValue);
geolocation.watchLocation(function(loc) {
vm.set("altitude", loc.altitude);
vm.set("longitude", loc.longitude);
console.log(vm.get("altitude")); // Observable model updated
console.log(vm.get("longitude"));
})

Categories

Resources