On Page A, I have a s.tl() call on click of "Link A" where I am filling evar1 and triggering off an event1. This link A leads to Page B
Code on link click in page A
$(document).on('click','.nav.navbar-nav.subnav-breadcrumb a',function(){
if($(this).text().toLowerCase().indexOf('create group')!=-1){
s.events = "event1";
s.linkTrackEvents = "event1";
s.eVar1 = "Step 1";
s.linkTrackVars = "eVar1,events";
s.tl(true,'o','Step 1');
}
});
On pageload of Page B, in the do Plugins sections, I try to get the value of eVar set in the prev s.tl() call by the following code
function s_doPlugins(s) {
console.log(s.getPreviousValue(s.eVar1,'cookie_name','event1')
}
However, I get the value as 'undefined'. Does getPreviousValue() plugin not work on previous s.tl() calls? What am I doing wrong here?
As mentioned in the documentation, since you are using the 3rd argument of s.getPreviousValue(), it will only store and trigger if the specified event is set (in both your case and doc example, that is event1).
Since you are setting event in the link click, s.getPreviousValue() triggers because s_doPlugins gets called on all s.t() and s.tl() calls, so at that point you should see the value in your cookie_name cookie (look in s_pers cookie if you are using combined cookie plugin).
However, on the next page (Page B) event1 isn't set, so when s_doPlugins gets called for the on-page s.t() call, s.getPreviousValue() will not update/return previous value.
In other words, when you specify an event in the 3rd argument, the plugin only triggers when the specified event is present in s.events. Basically first thing it does is check if 3rd arg exists then go through s.events and see if it's in there. If it's not, that's it, function ends with no return value (and that's why you get undefined returned).
I'm not sure what you're actually trying to accomplish but in my experience there aren't many use cases for specifying an event in the 3rd argument.
Related
I have setup a Custom JavaScript variable that works intermittently. The function is simply designed to return true or false if a text is contained on the page.
The below code works fine when the page is loaded directly from the URL bar and when executed in the developer tools console. When running the function in the console, the function indeed turns true. When the code is executed within debug mode in GTM, the value returns false when a history change event occurs.
function() {
var content = document.body.innerText;
var query = "text to search";
if (content.search(query) > -1 ) {
return true;
} else {
return false;
}
}
Any assistance/insight is very much appreciated!
To me this seems like expected behavior. Since you are talking about history changes, you are probably working with a single page application, or some other page where the DOM is changed after the initial page load.
Custom Javscript variables evaluate a function and return the result each time you reference it. How I imagine the flow of operations goes is this.
Page Loads (target text is in the page body) -> Custom JS evaluates on page view and returns true -> User presses some button -> DOM is modified to display new content (target text is removed and no longer present -> History change occurs -> Custom JS evaluates again, the text is no longer present so returns false.
If the target text is still present after the history change, then I can understand why we have some unexpected behavior. The history change trigger is based off of the push state api so what could be happening is that the pushState() function is called before the DOM is finished being modified. In this case, the text isn't present at time of the history change event even though it is shortly afterwards.
You could change the page so pushState() is only called after the DOM is done being modified, use a custom event as a trigger instead (again, pushing it after the DOM is done being modified), or use a different trigger like the element visibility trigger that will only fire after the new DOM elements you want to target appear on-screen.
I came across a peculiar issue when trying to make an ajax call and isolate the actions of the function to itself. Here is the code snippet
$(document).on('click', 'input.action', function(event) {
var self = this;
$.ajax({
url:'http://date.jsontest.com/',
method:'GET',
cache:false,
dataType:'json',
success:self.process,
error:function(){self.process(false);}
});
self.process = function(data) {
if (data) {
alert(data.time);
}
else {
alert("Operation Failed!");
}
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<div class="container">
<input type="button" value="Get Time" class="action"/>
</div>
Let me briefly explain what I am trying to do, on click of the button, I wish to receive some data from the server and display the data. I am using a process function to process the received data. In case of an error I reuse the process function in a different way to display the error message. I simply use the self variable to contain all the elements within the parent function. I fully understand the following:
What I know
I do not have to use the self to contain the process function because another method will not have access to it
Because the process method in the snippet above is declared after the ajax call for the program as far as it is concerned the process function is undefined.
I clearly know how to fix it.
Experiment:
Click on the Get Time button
Wait for as long as you want but see no result, which is expected because of the process function is declared after the ajax call
Click on the Get Time button again
It works now! Some time (which is probably not your time :P) is displayed now!!
What I wish to know:
What just happened? why does it work the second time and everytime after? Remember this only works for ajax calls, if it were the case that the assignment is retained in the function after calling it once, then this should work in every situation but it does not. Here is an experiment to show that it does not work the same way when ajax calls are not used: Fiddle - Experiment
The Solution:
I am adding a sample solution based on #Felix Kling's answer below. In the Sample Solution, there are two buttons Get Time and Get Date. I've attached the parameter to retrieve time in case of Get Time and date in the case of Get Date to the object self and it is interesting that once I click on Get Time nothing happens just like before but if I click on either Get Time or Get Date the second time only time is displayed.
What just happened?
In a simplified way, this:
var process;
// First click
ajaxCall(process); // process is still undefined
process = function() { ... };
// second click
ajaxCall(process); // process is defined
process = function() { ... };
The assignment to self.process "persists" between events because self refers to the same element.
Here is an experiment to show that it does not work the same way when ajax calls are not used: ...
It doesn't work in your fiddle because of one big difference: you are trying to execute process immediately. But it doesn't exist, so an error is thrown. At this point the script terminates and won't execute the rest of the function, where the function definition takes place.
In your example here, the execution of process is delayed. The script "doesn't know" that there is no function to call until the response was received.
There is nothing "special" going on here. Yes, accepted that the first time it returns undefined as it is yet to be defined.
But, you're attaching the function to the same element input.action. So, the next time, when you click the button, this already has the process method attached to it, so gets called when clicked again.
Try adding one more button with same class and click each once. Now though you've clicked the first button, clicking the second button will still not create an alert as it has not yet had the process function attached to it.
I want to store the current tab url in the following <input> field:
<input type="text" id="pdurl" value=>
The code I wrote in popup.js is the following:
chrome.tabs.query({active : true, currentWindow: true}, function (tabs) {
var tab = (tabs.length === 0 ? tabs : tabs[0]);
var activeTabUrl = tab.url;
});
document.getElementById("pdurl").innerHTML = var activeTabUrl;
I already have the tabs permission set in manifest file.
Your code is totally wrong. There are some serious problems, which would have been easy to avoid checking the popup console for errors. Here they are:
First of all chrome.tabs.query is an asynchronous method. This means that the code is evaluated and queued to be executed; when it executes, the callback function (which you're specifying as second argument) is called and executed. This means that the last line you wrote will always fail because the variable you want to use still doesn't exist (the query function hasn't still finished working).
You are creating a useless (and wrong (because you're assigning an array to it)) variable inside the callback: there's no need of your tab variable, because querying an active tab in the current window always returns a single tab, so you just need to use tabs[0].
Your activeTabUrl variable is defined with the var keyword, which will make it private, and you won't be able to use it outside the function (which is what you're trying to do in the last line, althought it's still wrong).
In the last line you are trying to assign the variable you created in the callback function to the innerHTML of your input: this statement is so wrong on so many levels I don't even know where to start: first of all if you want to actually see something in the text input you have to modify its value; secondly: the variable is not defined; plus, the var statement in your assignment makes it syntactically wrong; fourth: even doing all of the three previous conditions right you still are out of the callback.
Stated the above, this is the correct code for what you're trying to do:
chrome.tabs.query({active : true, currentWindow: true}, function (tabs) {
document.getElementById("pdurl").value = tabs[0].url;
});
I strongly recommend you to take a look at some JavaScript tutorial, and to check the console for errors* before asking questions like this one.
* Errors in the popup of an extension are shown in the popup console, which you can open right clicking on the extension's icon and choosing "Inspect popup".
I have a problem with my code, some code does not work when I call recursive call of same function inside it. It has to be something with myGalleria = Galleria.get(0);, but I have no idea how to make it all work.
Document Ready (just to show when I call function for the first time, everything works fine for first time)
$(document).ready(function(){
$.getJSON('getImages.php', {
cat: "123"
}, function(imgData){
createGallery(imgData);
});
});
Now function itself, note that when I click on .galleria-menuButtons span that calls same function nothing is working, well galleria itself is creating, but nothing else.
function createGallery(imgData){
$("#gallery").galleria({
image_margin: 30,
clicknext: true,
transition: "fade",
dataSource: imgData
});
myGalleria = Galleria.get(0); // I don't think this works after recursive call
// Adding menu and menu buttons
myGalleria.addElement("menu").appendChild("container", "menu");
myGalleria.addElement("menuButtons").appendChild("menu", "menuButtons");
$.ajax({
url: "menuButtons.php",
success: function(data){
myGalleria.$("menuButtons").html(data);
}
});
// Menu button click events
$('.galleria-menuButtons span').live('click', function(){
alert(this.id);
// Getting jSon data
$.getJSON('getImages.php', {
cat: this.id
}, function(imgData) {
alert(imgData);
createGallery(imgData); // <- Recursive call
});
});
}
I have similar function on window.resize and it also does not work after recursive call.
$(window).resize(function(){
$(".galleria-container").css("width", $(window).width());
$(".galleria-container").css("height", $(window).height());
galleriaRescale = Galleria.get(0);
galleriaRescale.rescale(); // <- this is not working either
//sizeBG();
});
FYI - this isn't actually recursion in the traditional sense because you're calling createGallery from a click handler which launches a JSON request which then calls createGallery when that succeeds, both of which will occur after the previous call to createGallery finishes.
But you do have surviving function closures which could be confusing things or causing problems. One guess is that you may want to make sure that things you expect to be local variables (like myGalleria have a var in front of them so they really are local variables and not variables that might be scoped to a higher level and be influenced by a previous incarnation of this call or be influencing an earlier call that hasn't yet completed.
var myGalleria = Galleria.get(0);
Then, assuming imgData is some sort of data structure like an array or object, you have to make sure that there's either only one global version of that data structure that never changes or that each call of createGallery has the appropriate separate copy of that data structure. If it's getting changed along the way, then subsequent calls to createGallery may not be getting the data they want. If it's a read-only data structure (you don't change it), then you're probably OK on that one.
OK, let's talk through the pseudo code for what this does.
On page ready, you get some JSON image data.
When that succeeds, you call createGallery with that image data.
The createGallery call does some sort of operation in the DOM (perhaps an animation)
It then calls: myGalleria = Galleria.get(0); Because there is no var in front of myGalleria, this is a global variable declaration (bad news for recursion and closures)
You then use the myGalleria data structure to make some changes to the DOM (adding menus and menu items).
You then add a .live click handler on a pretty generic set of CSS classes (it's possible you have added this click handler more than once here).
You then fetch some JSON image data again.
When that image data is fetched, you start the whole process over again by called createGallery.
Summary
The two potential problems I see are that myGalleria is not a local variable and probably should be and you may be adding duplicate click handlers.
If neither of these fully solve the issue, then we probably need more information about what Galleria.get(0) is doing.
FYI, the resize clickHandler looks like it may have the same issue with not using var to make your variable declaration a local variable.
Round 2
OK, here are some more observations.
When you add the menu and menu buttons with this block of code, you aren't providing any unique identifiers to either the addElement or appendChild functions (you're providing "menu" and "menuButtons" to both). As such, I don't know how you can uniquely hook up to them in the subsequent click event. As far as your code looks, all the menu items look identical and none have unique state. I don't know the Galleria code, but I assume somebody has to make unique identifiers for these new items so that you can uniquely identify them in your subsequent click handler.
// Adding menu and menu buttons
myGalleria.addElement("menu").appendChild("container", "menu");
myGalleria.addElement("menuButtons").appendChild("menu", "menuButtons");
When you set up a click handler to presumably handle the clicks for just these menu items, you are using the exact same CSS selector every time so there's no way that this click handler is going to be uniquely assigned to just the newly create menu items (which is what I assume you want). I don't know the Galleria code, but I assume that you should create some sort of unique ID that you pass into addElement and appendChild for the newly created menu items and then reference that unique identifier when you install the click handler. Likewise, this function needs to uniquely target just the menu buttons you created by using unique identifiers myGalleria.$("menuButtons").html(data);
Lastly, I'd suggest you change the name of one of your variables just to avoid confusion. In your click handler, change the three occurrences of imgData to just data so there can be no confusion about closures and the value of imgData.
Round 3
Ultimately one of the fixes was this (embedded in the comments):
I think it might work if you just only install the .live click handler once outside the createGallery function rather than call it each time. Since it's .live it will automatically work for all future buttons you create so you should only call it once. I'd suggest putting it in the $(document).ready function block.
I'm developing a small plugin that changes the favicons if there are unread messages in mailbox in Roundcubemail. However, the API sucks, and the event listupdate is fired only when the whole page is loaded, even if it is meant to fire when the list is updated.
However, I've managed to find out, that every time the list is updated, certain functions are called, such as set_unread_count. It gets the unread-count easily, so it would be great to somehow "append" stuff to this function. I just think based on hours of searching that there is no solution for this. Can I add a callback to be called when the set_unread_count is called? Can I somehow append stuff to that function? Any other ideas?
Create a little hook.
var _old_set_unread_count = set_unread_count;
set_unread_count = function() {
// do whatever you want here
// access arguments[x] to get arguments.
_old_set_unread_count.apply(this, arguments);
};
Demo: http://www.jsfiddle.net/4yUqL/69/