Following the docs on https://developers.google.com/custom-search-ads/docs/implementation-guide I created some code to retrieve ads on a search result page.
This code assumes that you place a container on your webpage where the function
new google.ads.search.Ads(pageOptions, adblock1, adblock2);
appends an iFrame to that may contain ads. I say MAY contain, because sometimes the iFrames stay empty.
Question:
Now I need to know weather there are any ads displayed in the containers or not. How do I do this?
The call is a-synchronous, so when do I initialise the check? (the google reference does not note a callback function)
How do I check if there's an ad shown. Because with Javascript I can't look inside the iFrame..
Any suggestions welcome! :)
Regards,
Jorn
the callback function, that maybe helps you is:
'noAdLoadedCallback':
function(containerName, adsLoaded) {
if (!adsLoaded) {
try {
---- do something here ---
}
catch (e) {}
}
}
You can put this on each adblock.
Cheers
Nik
Today I faced the same problem, and based on the response from #Niko Nik the solution that worked for me is the following one:
AppComponent.prototype.prepareAds = function (containerId, nOfAds, query) {
var csa = window._googCsa || function () {};
var self_1 = this;
var pageOptions = {
'pubId': this.gootleAdClient,
'adtest': this.googleAdTest,
'adLoadedCallback': function adLoadedCallback(containerName, adsLoaded) {
self_1.adsLoaded[containerName] = adsLoaded;
}
};
var adBlock = {
'container': containerId,
'width': '100%',
'number': nOfAds
};
if (query) {
pageOptions['query'] = query;
}
this.adsLoaded[containerId] = true;
csa('ads', pageOptions, adBlock);
}
I found that adLoadedCallback has the advantadge that it's called when there are ads and when there are not (adsLoaded parameter is true when there are an false when there are not).
You could always add a MutationObserver and wait for the iframe to be inserted, then check its height. If it's less than 30 pixels tall, it's probably empty.
I haven't seen any callbacks in the CSA code, but I have seen two undocumented options for ad blocks, clicktrackUrl and linkTarget. One is a url for a tracking pixel that's loaded when ads are clicked, the other acts like the target attribute on an a tag.
Related
I've been working with Liferay 7 for a while and needed to create a feedback form with prefilled values. I created a feedback form and a page, where it's shown and where I could add Javascript.
The user clicks on a link ("Did you find this helpful? Yes/No") and it takes you to the feedback page with the page and answer as URL parameters.
URL: {feedback-page-url/} ?pageUrl=/services&answer=Yes
Now here's where the problems began. Liferay updates it's values very confusingly and while generic document.getElementsByName(...) etc. seemed to work at first, they updated back when clicking the page. The difficult thing is to update the right values in right elements, so they won't be overrun by Liferay.
I provided an answer to my question below. Feel free to ask me anything, I'll try to help :)
Full code block in the end!
So I found out a solution to this problem. Liferay creates an instance (_com_liferay...) and uses it's values to be up to date, so we need to get a hold of it and update it's values. You can do it manually by inspecting and finding your instance, but I have an automatic code that should get it for you.
The id we are searching for is for DDMFormPortlet and the String we get this way is close to perfect. The String that document.querySelector() finds begins with p_p_id_com..., so we can use .substring to remove the unnecessary part and then add +"form" in the end to make it complete. If you find a better way to find this, please share it :)
// _com_liferay_dynamic_data_mapping_form_web_portlet_DDMFormPortlet_INSTANCE_randomkey_form
const idFinder = function() {
const idString = document.querySelector('[id*="DDMFormPortlet"]').id;
return(idString.substring(6) + "form");
}
Now that we have the correct String text, we'll find the element, that corresponds to it:
const formFieldArray = window[idFinder()];
Now if you try it just by itself, it most likely won't find anything, because it's loads slowly. I put all of this into try-catch with setTimeout() to make sure everything works as intended. Now all we need to do is collect the information from our URL and set it to the correct places.
const params = new URLSearchParams(location.search);
const formAutoFiller = function (params) {
try {
const formFieldArray = window[idFinder()];
// make sure you have the numbers according to your form!
formFieldArray.pages[0].rows[0].columns[0].fields[0].value=params.get('pageUrl');
formFieldArray.pages[0].rows[1].columns[0].fields[0].value=params.get('answer');
// ...
}
}
And finally, as the changed values update to the form after clicking an input field, we'll move the selection focus to one of the input fields after the other code is ran:
document.getElementsByClassName("ddm-field-text")[1].focus();
A bit cleanup for myself and we're done! Full Javascript here:
const params = new URLSearchParams(location.search);
const idFinder = function() {
const idString = document.querySelector('[id*="DDMFormPortlet"]').id;
return(idString.substring(6) + "form");
}
const formAutoFiller = function (params) {
try {
const formFieldRows = window[idFinder()].pages[0].rows;
formFieldRows[0].columns[0].fields[0].value=params.get('pageUrl');
formFieldRows[1].columns[0].fields[0].value=params.get('answer');
document.getElementsByClassName("ddm-field-text")[1].focus();
} catch (e) {
setTimeout(formAutoFiller, 500, params);
}
}
formAutoFiller(params);
I have a feeling this is a simple issue I'm missing but after a couple of hours I've given up and decided to post in here.
I'm trying to implement a generic paging partial view that I can use across the entire site. As a result the paging model takes a function that will be bound to the paging controls that is used as a callback at a later time. See UpdateFunction below.
ViewModels.Shared._PaginationPartialViewModel pagination =
new ViewModels.Shared._PaginationPartialViewModel()
{
CurrentPage = Filter.Page,
ItemFrom = GenericHelpers.Paging_GetItemFrom(10, Filter.Page, TotalItems),
ItemTo = GenericHelpers.Paging_GetItemTo(10, Filter.Page, TotalItems),
TotalItems = TotalItems,
TableClass = Filter.Table,
TotalPages = (int)Math.Ceiling((double) TotalItems / 10),
UpdateFunction = "getTransfers('" + Filter.Table + "')"
};
Now when the model is bound to the view, this function is passed in as a callback to a javascript click event paginationClick() like so...
#Model.CurrentPage
The paginationClick() function fires, but when checking the dev console the callback method appears to be firing first. Here's the paginationClick() method... (I know that the page parameter is not currently being utilized btw!)
function paginationClick(control, page, callback)
{
if (!$(control).hasClass('stock-pagination__action_state_active')) {
$(control).parent().find('a').each(function () {
$(this).removeClass('stock-pagination__action_state_active');
});
$(control).addClass('stock-pagination__action_state_active');
callback;
}
}
I anyone can offer an extra pair of eyes it would be much appreciated!
I found a work around with this, instead of passing getTransfers in as a callback, I appended it to the control as a data-attribute then used eval to execute at the correct time like so:
data-callback="#Model.UpdateFunction"
and then
function paginationClick(control, page)
{
if (!$(control).hasClass('stock-pagination__action_state_active')) {
var arr_Controls = [];
$(control).parent().find('a').each(function () {
$(this).removeClass('stock-pagination__action_state_active');
arr_Controls.push($(this));
});
$(control).addClass('stock-pagination__action_state_active');
eval($(control).attr("data-callback"));
//callback;
}
}
It's not the solution I was after but it works. If anyone has any idea how to get it working as a callback please let me know.
I have a filter_horizontal selector in my Django admin that has a list of categories for products (this is on a product page in the admin). I want to change how the product change form looks based on the category or categories that are chosen in the filter_horizontal box.
I want to call a function every time a category is moved from the from or to section of the filter_horizontal.
What I have now is:
(function($){
$(document).ready(function(){
function toggleAttributeSection(choices) {
$.getJSON('/ajax/category-type/', { id: choices}, function (data, jqXHR) {
// check the data and make changes according to the choices
});
}
// The id in the assignment below is correct, but maybe I need to add option[]??
var $category = $('#id_category_to');
$category.change(function(){
toggleAttributeSection($(this).val());
});
});
})(django.jQuery);
The function never gets called when I move categories from the left side to the right side, or vice versa, of the filter_horizontal.
I assume that $category.change() is not correct, but I don't know what other events might be triggered when the filter_horizontal is changed. Also, I know there are multiple options inside of the select box. I haven't gotten that far yet, but how do I ensure all of them are passed to the function?
If anyone can point me in the right direction I would be very grateful. Thank!
You need to extend the SelectBox.redisplay function in a scope like so:
(function() {
var oldRedisplay = SelectBox.redisplay;
SelectBox.redisplay = function(id) {
oldRedisplay.call(this, id);
// do something
};
})();
Make sure to apply this after SelectBox has been initialized on the page and every time a select box refreshes (option moves, filter is added, etc.) your new function will be called.
(Code courtesy of Cork on #jquery)
I finally figured this out. Here is how it is done if anyone stumbles on this question. You need to listen for change events on both the _from and _to fields in the Django filter_horizontal and use a timeout to allow the Django javascript to finish running before you pull the contents of the _from or _to fields. Here is the code that worked for me:
var $category = $('#id_category_to');
$category.change(function(){
setTimeout(function () { toggleAttributeSection(getFilterCategoryIds()) }, 500);
});
var $avail_category = $('#id_category_from');
$avail_category.change(function(){
setTimeout(function () { toggleAttributeSection(getFilterCategoryIds()) }, 500);
});
And this is how I get the contents of the _to field:
function getFilterCategoryIds() {
var x = document.getElementById("id_category_to");
var counti;
var ids = [];
for (counti = 0; counti < x.length; counti++) {
ids.push(x.options[counti].value);
}
return ids;
}
I know it was a convoluted question and answer and people won't come across this often but hopefully it helps someone out.
I recently ran into a familiar javascript/jQuery timing bug and spent too long debugging it. What I need is a smarter debugging path for this problem.
In specific, my issue was that user inputs were supposed to be causing a Mongo database call and the results were sent, after a little math, to displayed outputs. But the displayed outputs were crazily wrong. However, once I added a FireBug break point the problem went away. At that point I knew I had a timing issue, but not how to solve it.
Here are the relavant pieces of code before the error:
handleDataCallBack : function(transport) {
var response = $.parseJSON(transport);
if(!hasErrors) { this.updatePage(response); }
},
accessDatabase : function(){
var params = { ... };
DAL.lookupDatabaseInfo(this.handleCallBackOutputPanel, this, params);
},
calculateValues: function() {
// some numerical values were updated on the page
}
onDomReady : function() {
// ...
//bind drop-down select change events
$('#someDropDown').change(function() {
me.accessDatabase();
me.calculateValues();
});
}
To fix the problem, all I had to do was move the "calculateValues" method from the onDomReady inside the call back:
handleDataCallBack : function(transport) {
var response = $.parseJSON(transport);
this.calculateValues();
if(!hasErrors) { this.updatePage(response); }
},
The problem was that the database hadn't responded before the calculations were started. Sure, that's easy to spot in retrospect. But what methods can I use to debug asynchronous timing issues in javascript/jQuery in the future? This seems well outside the context of IDE tools. And FireBug didn't help. Are there any tools for tracking down asynchronous web development issues? Or maybe some time-tested methods?
i assume your problem is caused here:
$('#someDropDown').change(function() {
me.accessDatabase();
me.calculateValues();
});
this issue is that your calculations are done just right after the call. seeing that the DB call is async, calculate does not wait for it. however, you can do it using "callbacks". i see you do try to implement it and yes, it is correct. however, i find this more elegant:
calculateValues: function() {
// some numerical values were updated on the page
},
//since this is your general callback hander
//you hand over the return data AND the callbackAfter
handleDataCallBack: function(transport, callbackAfter) {
var response = $.parseJSON(transport);
//you may need to use apply, im lost in scoping here
callbackAfter();
//or
callbackAfter.apply(scope);
if (!hasErrors) {
this.updatePage(response);
}
},
accessDatabase: function(callbackAfter) {
var params = {};
//pass callbackAfter to the function,
//after this is done, pass it to the handler
DAL.lookupDatabaseInfo(this.handleCallBackOutputPanel, this, params, callbackAfter);
},
onDomReady: function() {
$('#someDropDown').change(function() {
me.accessDatabase(function() {
//send over what you want done after.
//we'll call it "callbackAfter" for easy tracing
me.calculateValues();
});
});
}
I want to display little messages to provide feedback to the user while he
is providing input or just interacting with the UI.
I need it for my firefox addon, so I have to develop it in plain javascript
and not jQuery.
I want the message to appear, but only one message can be visible at the same
time, so I need some kind of queue to manage incomming messages. After a certain time
e.g. 3 sec the message should fade away or just disappear.
For now I am able to add messages to the DOM. Any suggestions how to implement the queue
and how to push the messages forward according to the time?
Thanks!
Perheps you need the concept of FIFO (First In First Out)
Take a look at this simple example in plan java script language:
function Queue() {
var data = [];
this.isEmpty = function() {
return (data.length == 0);
};
this.enqueue = function(obj) {
data.push(obj);
};
this.dequeue = function() {
return data.shift();
};
this.peek = function() {
return data[0];
};
this.clear = function() {
data = [];
};
}
You can use jQuery in a firefox plugin:
Include a script tag in the xul file that points to the jQuery file, e.g.:
<script type="text/javascript" src="chrome://extensionname/content/jquery.js" />
In each js function that uses jQuery, insert this line:
$jQuizzle = jQuery.noConflict();
In each jQuery call, if you are trying to manipulate the document in the current browser window, you must supply the context as "window.content.document", like this:
$jQuizzle(".myClass", window.content.document).show();
Then you can use this jQuery plugin:
http://benalman.com/projects/jquery-message-queuing-plugin/
It's not clear what sort of message you want to display. The nsIAlertsService can display messages but I'm not sure how well it queues them. If you want something simpler then perhaps you could just show a custom <tooltip> element.