I am ajaxing in new buttons after each successful http request.
//Remove events and items
$('#sthoverbuttons-chicklets span').remove();
I then add new items with new events in by passing an object into stwidget.
See here documentation for sharethis: http://support.sharethis.com/customer/portal/articles/475079-share-properties-and-sharing-custom-information#Dynamic_Specification_through_JavaScript
//Finish with share buttons
wyrAjax.sharethis.finishAddingShareButton();
wyrAjax.sharethis = {
//Grab the current share height so we can keep it this height when we remove all the items
shareThisHeight:null,
init:function () {
//If the height has not been set set it
if(wyrAjax.sharethis.shareThisHeight===null){
wyrAjax.sharethis.shareThisHeight = $('#sthoverbuttons').outerHeight();
}
//Set up elements so that we can use them as ID's
$('.sthoverbuttons-chicklets').attr('id', 'sthoverbuttons-chicklets');
if (!$('#shareLoading').length) {
$('#sthoverbuttonsMain').append('<div id="shareLoading"><img src="/img/loading.gif" style="position: absolute; top: 50%;left: 37%"></div>');
}
},
shareTypes:function(){
var array = [];
array[0]={
"service":"facebook"
};
array[1]={
"service":"twitter"
};
array[2]={
"service":"delicious"
};
array[3]={
"service":"googleplus"
};
array[4]={
"service":"reddit"
};
array[5]={
"service":"tumblr"
};
array[6]={
"service":"stumbleupon"
};
array[7]={
"service":"digg"
};
array[8]={
"service":"sharethis"
};
return array;
},
startGettingShareButton:function () {
//First we run a quick check to see if the elemnts have ID's
wyrAjax.sharethis.init();
//Now lets fade out and clean up all the shares so we can add new shares in.
$('#sthoverbuttons-chicklets').hide();
$('#sthoverbuttonsMain').height(wyrAjax.sharethis.shareThisHeight);
wyrAjax.sharethis.addLoadingToShare();
},
addLoadingToShare:function () {
$('#shareLoading').show();
$('#sthoverbuttons-chicklets span').off().remove();
},
finishAddingShareButton:function () {
$('#shareLoading').hide();
var shareItems = wyrAjax.sharethis.shareTypes();
$.each(shareItems,function(key, value){
wyrAjax.sharethis.addShareThisButton(value);
});
$('.sthoverbuttons-chicklets').show();
},
addShareThisButton:function (object) {
stWidget.addEntry({
"service":object.service,
"element":document.getElementById('sthoverbuttons-chicklets'),
"url":"http://www.wouldyourathers.co.uk/question/" + wyrAjax.questionDetails.id,
"title":"Would You Rather | " + wyrAjax.questionDetails.q1,
"type":"large",
"text":"Would You Rather " + wyrAjax.questionDetails.q1 + " or " + wyrAjax.questionDetails.q2,
"summary":wyrAjax.questionDetails.q1 + " or " + wyrAjax.questionDetails.q2
});
}
};
When I click one of the newly added buttons it will go to for example the share feature of twitter, but it will also bring up for some reason Facebook's share.
I believe I want to remove all events on the spans before I re-add them.
So the problem i was having is that sharethis doesn't want you remove the share items. Sharethis stWidget.addEntry doesn't want to you to add new dom items, it wants you to replace the current share butons already on the page.
With this in mind i edited my code to add ID's to all buttons already shared:
//Give all share buttons ID's
var shareItems = wyrAjax.sharethis.shareTypes();
$.each(shareItems,function(key, value){
$('.st_'+value.service+'_large').attr('id','st_'+value.service+'_large');
});
Then i used Sharethis's addEntry to just replace the existing button.
wyrAjax.sharethis = {
//Grab the current share height so we can keep it this height when we remove all the items
shareThisHeight:null,
init:function () {
//If the height has not been set set it
if(wyrAjax.sharethis.shareThisHeight===null){
wyrAjax.sharethis.shareThisHeight = $('#sthoverbuttons').outerHeight();
}
//Set up elements so that we can use them as ID's
$('.sthoverbuttons-chicklets').attr('id', 'sthoverbuttons-chicklets');
if (!$('#shareLoading').length) {
//Give all share buttons ID's
var shareItems = wyrAjax.sharethis.shareTypes();
$.each(shareItems,function(key, value){
$('.st_'+value.service+'_large').attr('id','st_'+value.service+'_large');
});
$('#sthoverbuttonsMain').append('<div id="shareLoading"><img src="/img/loading.gif" style="position: absolute; top: 50%;left: 37%"></div>');
}
},
shareTypes:function(){
var array = [];
array[0]={
"service":"facebook"
};
array[1]={
"service":"twitter"
};
array[2]={
"service":"delicious"
};
array[3]={
"service":"googleplus"
};
array[4]={
"service":"reddit"
};
array[5]={
"service":"tumblr"
};
array[6]={
"service":"stumbleupon"
};
array[7]={
"service":"digg"
};
array[8]={
"service":"sharethis"
};
return array;
},
startGettingShareButton:function () {
//First we run a quick check to see if the elemnts have ID's
wyrAjax.sharethis.init();
//Now lets fade out and clean up all the shares so we can add new shares in.
$('#sthoverbuttons-chicklets').hide();
$('#sthoverbuttonsMain').height(wyrAjax.sharethis.shareThisHeight);
wyrAjax.sharethis.addLoadingToShare();
},
addLoadingToShare:function () {
$('#shareLoading').show();
},
finishAddingShareButton:function () {
//Remove the loading.gif
$('#shareLoading').hide();
//grab array of different share types
var shareItems = wyrAjax.sharethis.shareTypes();
//Loop through
$.each(shareItems,function(key, value){
wyrAjax.sharethis.addShareThisButton(value);
$('#st_'+value.service+'_large > span:first-child').remove();
});
$('.sthoverbuttons-chicklets').show();
},
addShareThisButton:function (object) {
stWidget.addEntry({
"service":object.service,
"element":document.getElementById('st_'+object.service+'_large'),
"url":"http://www.wouldyourathers.co.uk/question/" + wyrAjax.questionDetails.id,
"title":"Would You Rather | " + wyrAjax.questionDetails.q1,
"type":"large",
"text":"Would You Rather " + wyrAjax.questionDetails.q1 + " or " + wyrAjax.questionDetails.q2,
"summary":wyrAjax.questionDetails.q1 + " or " + wyrAjax.questionDetails.q2
});
}
};
Hopefully somebody can find this helpful.
Related
I am trying to convert an older jquery script to vanilla JS.
I have been working through most of them just one by one but am having a problem with the ajax call. Can anyone look at my original file and new file and see what is missing?
I am struggling mostly with converting the initial function calls to vanilla js. If you look at the 2nd code drop there most of the 'jquery-isms' have been rewritten in vanilla js. However I am having trouble converting my $.merge and $.extend actions. Furthermore, converting the $.ajax call to a JS version.
I tried to work on it modularly task by task but still haven't gotten it completely polished.
Jquery
(function($){
$(document).ready(function() {
$.ajax({
url: "https://api.flickr.com/services/rest/?method=flickr.galleries.getPhotos&api_key=*PRIVATE*c&gallery_id=72157720949295872&per_page=10&format=json&nojsoncallback=1",
type: "GET",
success: function(data) {
console.log("api successfully called")
let path = data.photos.photo
//for each photo, I save the different individual ids into variables so that they can be easily plugged into a URL
for (let i = 0; i < path.length; i++) {
let obj = path[i];
let farm_id = data.photos.photo[i].farm
let server_id = data.photos.photo[i].server
let photo_id = data.photos.photo[i].id
let secret = data.photos.photo[i].secret
//the static address to photos on Flickr is accessed through this address: https://farm{farm-id}.staticflickr.com/{server-id}/{id}_{secret}.jpg
//this variable is the direct link to access photos on Flickr, minus the ".jpg" designation that will be added, according to whether we are trying to access the medium picture or the large picture
let pic_url = "https://farm" + farm_id + ".staticflickr.com/" + server_id + "/" + photo_id + "_" + secret;
//this is the variable that stores the medium jpeg URL
let pic_url_m = pic_url + "_m.jpg";
//this stores an image tag which will be populated with a medium jpeg URL
let pic_img = ('<img src=\'' + pic_url_m + '\' alt = \"pic\" />');
//this appends the var pic_img to the photo_list div as the function loops through
//$('.body').append('#frame');
$('#photo-list').append(pic_img);
//this appends the class "paginate" to each img tag that is formed, ensuring that the the divs get passed to a later function called customPaginate
// $('img').addClass("paginate")
$('#photo-list img').addClass("paginate");
}
//this passes all divs with the class "pagination" to the function customPaginate
$('.pagination').customPaginate({
itemsToPaginate: ".paginate"
});
//when img tags with the class paginate are clicked, the following function is called
$('.paginate').click(function() {
//this variable saves the "src" or URL of (this) which is any element with the class "paginate"
let src = $(this).attr('src');
//this variable takes the "src" variable, slices the last six characters, and replaces it with "_c.jpg", a large version of the image URL
let src_l = src.slice(0, -6) + "_c.jpg";
//gives the "frame img" element a new attribute, which is the large image URL
$('#frame img').attr('src', src_l);
//allows the the "frame img" element to fade into the screen
$('#frame img').fadeIn();
//allows the "overlay" element to fade onto the screen
$('#overlay').fadeIn();
//when the "overlay" element is clicked, both the "overlay" and "frame img" elements
$('#overlay').click(function() {
$(this).fadeOut();
$('#frame img').fadeOut();
//removes the "src" attribute from "frame img", allowing it to be populated by other image URLs next time an image is clicked
$('#frame img').removeAttr('src');
});
});
}
});
});
//this function generates the customPaginate function, which paginates the images 10 to a page
$.fn.customPaginate = function(options)
{
let paginationContainer = this;
let defaults = {
//sets how many items to a page
itemsPerPage : 10
};
let settings = {};
//merges defaults and options into one one variable, settings
$.extend(settings, defaults, options);
//sets how many items will be on each page
let itemsPerPage = settings.itemsPerPage;
//sets which items are going to be
let itemsToPaginate = $(settings.itemsToPaginate);
//determines how many pages to generate based on the amount of items
let numberOfItems = Math.ceil((itemsToPaginate.length / itemsPerPage));
//this ul will contain the page numbers
$("<ul></ul>").prependTo(paginationContainer);
//loops through the ul tag the same number of times as there are pages. in this case, the loop will run 4 times
for(let index = 0; index < numberOfItems; index++)
{
paginationContainer.find('ul').append('<li>'+ (index+1) + '</li>');
}
//ensures that the current page only displays the items that should be on the specific page, and hides the others
itemsToPaginate.filter(":gt(" + (itemsPerPage - 1) + ")").hide();
//locates the first li element, adds activeClass element to it
paginationContainer.find("ul li").first().addClass(settings.activeClass).end().on('click', function(){
let $this = $(this);
//gives current page the activeClass setting
$this.addClass(settings.activeClass);
//takes activeClass setting away from non-current pages
$this.siblings().removeClass(settings.activeClass);
let pageNumber = $this.text();
//this variable designates that items located on the previous page times the number of items per page should be hidden
let itemsToHide = itemsToPaginate.filter(":lt(" + ((pageNumber-1) * itemsPerPage) + ")");
//this function merges itemsToHide and itemsToPaginate that are greater than the product of the pageNumber and the itemsPerPage minus 1, ensuring that these items are hidden from view
$.merge(itemsToHide, itemsToPaginate.filter(":gt(" + ((pageNumber * itemsPerPage) - 1) + ")"));
//designates these items as items that should be shown on the current page
let itemsToShow = itemsToPaginate.not(itemsToHide);
//hides items from other pages and shows items from current page
$("html,body").animate({scrollTop:"0px"}, function(){
itemsToHide.hide();
itemsToShow.show();
});
});
}
}(jQuery));
Vanilla JS (what im still stuck on)
(function($){
document.querySelector(document).ready(function() {
$.ajax({ //need to convert this to JS
url: "https://api.flickr.com/services/rest/?method=flickr.galleries.getPhotos&api_key=*PRIVATE*c&gallery_id=72157720949295872&per_page=10&format=json&nojsoncallback=1",
type: "GET",
success: function(data) {
console.log("api successfully called")
// ....truncated
}
});
});
$.fn.customPaginate = function()
{
let paginationContainer = this;
let defaults = {
itemsPerPage : 10
};
let settings = {};
//need to convert this extend to JS
$.extend(settings, defaults, options);
let itemsPerPage = settings.itemsPerPage;
// ....truncated
let pageNumber = qS.text();
let itemsToHide = itemsToPaginate.filter(":lt(" + ((pageNumber-1) * itemsPerPage) + ")");
//need to convert this extend to JS
$.merge(itemsToHide, itemsToPaginate.filter(":gt(" + ((pageNumber * itemsPerPage) - 1) + ")"));
});
}
}(jQuery));
First, please see: https://www.w3schools.com/js/js_ajax_intro.asp
Example you might consider.
function getPages(){
const xmlhttp = new XMLHttpRequest();
xmlhttp.onload = function() {
// Everything you want to do with the data
// this.responseText.photos.photo
}
xmlhttp.open("GET", "https://api.flickr.com/services/rest/?method=flickr.galleries.getPhotos&api_key=*PRIVATE*c&gallery_id=72157720949295872&per_page=10&format=json&nojsoncallback=1",);
xmlhttp.send();
}
I was building a code in javascript, and I have changed the organization of it following the format as I separated the functions as methods into objects and each method calls the other. My previous code was working fine, but this one for some reason is not.
Briefly explaining my code:
My code will create pictures of the cats listed in the model, also it creates a sidebar that holds the names of the cats. Afterwards, it will add event listeners to the pictures and the sidebar elements when I click on the name it'll show the cat pictures. The picture is also clickable; Therefore, when it is clicked it'll increment the number of clicks on the bottom of the picture.
I hope this would help reading the code make more sense.
Hope to get some help, please.
Thank you
/* ================= Model ================= */
//creating an array object that holds all the cats in it
var model = {
cats: [
{
"name": "Poplinre",
"image": "poplinre.jpg",
"clicks": 0
},
{
"name": "Chewie",
"image": "chewie.jpg",
"clicks": 0
},
{
"name": "Snow",
"image": "snow.jpg",
"clicks": 0
},
{
"name": "Cowboy",
"image": "cowboy.jpg",
"clicks": 0
}
]
};
/*=============== Octopus ==================*/
var octopus = {
init: function(){
view.createCats();
view.navBarSide();
},
//function that loads the page and then add eventlistener to each image
addImgListeners: function(){
let idList = document.querySelectorAll("img");
let elemArray = [...idList];
elemArray.forEach( function(elem) {
elem.addEventListener('click', function(e){
octopus.increaseClick(e);
}, false);
});
},
//function that increases the clicks with every click
increaseClick: function(e){
let element = e.target.classList[0];
cats[element].clicks +=1;
view.postClick(element);
},
//function that adds listeners to the side bar
listListeners: function(){
document.getElementById("list").addEventListener('click', function(e){
let targetPic = e.target.innerHTML;
let parentTarget = document.querySelector("."+targetPic+"").parentElement;
view.showPic(parentTarget);
});
}
};
/*============== View ===================*/
var view = {
//view model bulding the view
//function that creates the cats in the dom element
createCats: function(){
let addingCats = "";
(model.cats).forEach(function(cat, catIndex, cats){
addingCats += "<div class='catsP' style='display:none;'><div class='nameC "+cat.name+"'>" + cat.name +"</div><img src='" + cat.image + "' class='"+catIndex.toString()+"'><div id='" + catIndex.toString() + "'>" + cat.clicks.toString() + "</div></div>";
});
var picDiv = document.getElementById("main");
picDiv.innerHTML = addingCats;
octopus.addImgListeners();
},
//function that opens the cat needed and hides it
showPic: function(x){
if (x.style.display === "none") {
x.style.display = "block";
} else {
x.style.display = "none";
}
},
// view model bulding the nav bar side
//function that adds cats to the navbar
navBarSide: function(){
let barEl = document.getElementById("list");
(model.cats).forEach( function(cat, catIndex, cats){
barEl.innerHTML += "<li><a>"+ cat.name +"</a></li>";
});
octopus.listListeners();
},
//post the click to the image to show the user
postClick: function(el){
document.getElementById(""+el+"").innerHTML = "Clicks: " + model.cats[el].clicks;
}
};
document.onload = function(){
octopus.init();
};
Use window.onload instead of document.onload. Latter fires when DOM is ready, which may happen before images/scripts are loaded. window.onload waits for a full document being loaded.
There's other small(er) mistakes, as mentioned in comments.
I'm using jQuery to get a list of elements that contain certain key words. I'm able to get the list of elements but I don't know how to loop through each element, click on its child element and download the newly loaded page. Here's the casperjs code I have so far:
var casper = require('casper').create({
clientScripts: ["/var/www/html/project/public/js/jquery-3.3.1.min.js"]
});
var fs = require('fs');
casper.start('https://m.1xbet.co.ke/en/line/Football/', function () {
var links = casper.evaluate(function () {
$.expr[":"].contains = $.expr.createPseudo(function (arg) {
return function (elem) {
return $(elem).text().toUpperCase().indexOf(arg.toUpperCase()) >= 0;
};
});
return $("#events-betting").find("li.events__item_head:contains(World cup)");
});
var date = new Date(), year = date.getFullYear(), month = date.getMonth() + 1, day = date.getDate();
var folderName = year + '-' + month + '-' + day;
// loop would go here to save each file
var path = "destination/" + folderName + "/1xbet/worldcup-1";
fs.write(path + ".html", this.getHTML(), "w");
});
casper.run();
I'd like to click on the individual items on the links object - they aren't anchor tags but rather they are clickable divs with inline javascript listening for a click.
The goal is to click on the div that has certain text I'm interested in, then once clicked, I can either choose to scrape the HTML and save it in a file or get the current url; either will be fine for my purposes. Since there could be multiple divs with the desired text, I'd like for a way to loop through each and do perform the same operation.
This is an example of the page I'm interested in:
https://m.1xbet.co.ke/en/line/Football/
The parent element in this case is: #events-betting and nested is a list of li tags with clickable divs.
I can either choose to scrape the HTML and save it in a file or get the current url
Of course the solution is very specific to this exact site, but then again it is quite normal when doing web scraping.
casper.start('https://m.1xbet.co.ke/en/line/Football/', function () {
var links = casper.evaluate(function () {
$.expr[":"].contains = $.expr.createPseudo(function (arg) {
return function (elem) {
return $(elem).text().toUpperCase().indexOf(arg.toUpperCase()) >= 0;
};
});
var links = [];
// Better to scrpape .events__title as it contains data-href attribute
$("#events-betting").find(".events__title:contains(World cup)").each(function (i, item) {
var lastPartOfurl = item.getAttribute("data-href");
lastPartOfurl = lastPartOfurl.split("/");
links.push("https://m.1xbet.co.ke/en/line/Football/" + item.getAttribute("data-champ") + "-" + lastPartOfurl[1]+'/');
})
return links;
});
console.log(links);
});
The result:
https://m.1xbet.co.ke/en/line/Football/1536237-FIFA-World-Cup-2018/,https://m.1xbet.co.ke/en/line/Football/1204917-FIFA-World-Cup-2018-Winner/,https://m.1xbet.co.ke/en/line/Football/1518431-FIFA-World-Cup-2018-Special-bets/,https://m.1xbet.co.ke/en/line/Football/1706515-FIFA-World-Cup-2018-Teams-Statistics-Group-Stage/
I have set up features from an external geoJson file in Mapbox and bound popups to these features following the example at https://www.mapbox.com/mapbox.js/example/v1.0.0/custom-popup/
var myLayer = L.mapbox.featureLayer(bldgData).addTo(map);
myLayer.eachLayer(function(layer) {
// set up popup for each marker
var content = "";
var props = layer.feature.properties;
var imagePart = "<img class='popupPic' src='images/thumbnails/" + props.filename + "' ></img>";
var infoPart = "<h3 class='popupInfo'>" + props.bldgName + "</h3><p>" +
props.architect + "<br />" + props.year + "</p>";
content = imagePart + infoPart;
layer.bindPopup(content, {closeButton: false});
});
The popups are set up to display on mouseover...
myLayer.on('mouseover', function(e) {
e.layer.closePopup();
e.layer.openPopup();
});
myLayer.on('mouseout', function(e) {
e.layer.closePopup();
});
I have also set up filtering to display selected features following the example at https://www.mapbox.com/mapbox.js/example/v1.0.0/filtering-markers/
function chooseBldg(){
var bldgs = document.getElementById("buildingTypeMenu").value;
if(bldgs == "all") {
myLayer.setFilter(function(f) {return true;});
}
else {
myLayer.setFilter(function(f) {
return f.properties['buildingType'] === bldgs;
});
}
}
The popups display correctly when I first display the page, and the filters correctly select the subset of markers to display, but after the filter has been triggered the popups no longer display on mouseover. Do I need to rebind the popups (by explicitly triggering the eachLayer function or something) after the filter has been done?
Rebind popups solved this problem for me.
I'm making a website to host artwork. The idea is that when the page loads I have JavaScript run a php file that makes a query to the server to get the names and IDs of the image files (artwork.jpg) and display them as thumbnails on a page.
When you scroll over the thumbnail, the artwork is displayed larger on a different part of the screen and the description, specs, etc for the piece of art fades in. My issue is that when I make this second AJAX call it appends the value of the previously moused over image to the screen and does nothing until you've moused over at least two images.
Here's my code for the first ajax call that appends thumbnails to the page and creates a form with the value of the thumnbnail's id:
function getArtDescriptions()
{
$.post('../../path/to/script/get_art.php', function(json)
{
if (json.art.length > 0)
{
$.each(json.art,function()
{
var info =
'<div class = "thumbnail_box">'
+ '<img src = "images/thumbnails/'
+ this['img']
+ '"id = "'
+ this['ID']
+ '"> '
+ '<form id = "art_descriptions'
+ this['ID']
+ '" '
+ 'name = "art_descriptions'
+ this['ID']
+ '">'
+ '<input type = "hidden" id = "descriptions" name = "descriptions" value = "'
+ this['ID']
+ '"></form>'
+ '</div>';
});
}
}, 'json');
}
And this is the code I'm using to make the second AJAX call that is giving me a problem:
setTimeout(function get_id()
{
var tooltipTimeout;
$(".thumbnail_box img").on("mouseenter", function()
{
tooltipTimeout = setTimeout(details(this.id),0);
console.log(this.id);
});
$(".thumbnail_box img").on("mouseleave", function()
{
hideTooltip();
});
function hideTooltip()
{
clearTimeout(tooltipTimeout);
$(".description").fadeOut().remove();
}
}, 800);
//GRAB DESCRIPTIONS FROM DATABASE AND
function details(art)
{
var formname = "#art_descriptions"+art;
var filename = '../../file/path/to/script/get_descriptions.php';
//console.log($(formname).serialize());
$(".thumbnail_box img").on("mouseenter", function()
{
$.post(filename, $(formname).serialize(), function(json)
{
if (json.descriptions.length > 0)
{
//MAKE SURE TO EMPTY OUT DIV CLASSES FOR EACH TAB
$(".description").empty();
$.each(json.descriptions,function()
{
console.log("art method"+this['ID']);
$(".description").append(this['description']+this['ID']).hide().fadeIn("fast");
});
}
}, 'json');
});
};
When I console.log(this['ID']) in the get_id() method the correct value is displayed in the console, but when I console.log("art method"+this['ID'] in the details method I get a value equal to the previously scrolled over thumbnail's ID. I'd really appreciate any insight on this issue.
Is it something to do with the use of setTimeout()? My code would not run without specifying a timeout for the method. For example if I load the page and then scroll over images with ID's 14 and then 13, my console will display:
14
13
art method 14
The issue is that you are appending more of the same events. After the first mouseenter event occurs the details function is called, which then appends another mouseenter event. So subsequent calls will be doing the same thing. You can see an example of this here: http://jsfiddle.net/6qre72fk/.
var counter = 0;
$('#container1').on('mouseenter', function(){
$('#container2').text('First mouseenter');
appendingAnotherMouseEnter();
});
function appendingAnotherMouseEnter(){
$('#container1').on('mouseenter', function(){
$('#container2').text(counter);
counter++;
});
}
You can see how the counter is incremented several times due to all appended the mouseenter events.