I would like to create a custom plugin for tracking events in my JavaScript Application using Google Analytics Measurement Tool (GA MT), but I am a newbie and not sure how to write such plugin.
My idea about the plugin:
it should have defined all types of events I am going to track (i.e. starting of an application, button clicked, 1st, 2nd, ... slide entered, etc)
if I understand how GA MT works correctly, I will need to specify an event hit for each custom event (see more)
part of the hit parameters (url) is shared (such as version, client ID, tracking ID...)
the other part of the url is custom, so I will store the differences in various functions inside of the plugin
these functions will be later called i.e. on button clicked, on goToNextSlide etc, which will send a hit to GA.
This is an example of my plugin:
(function( $ ) {
var $_document = $(document);
// Shared hit parameters
var hit = 'https://www.google-analytics.com/collect?';
hit += 'v=1'; // Version.
hit += '&t=pageview'; // Pageview hit type.
hit += '&tid=UA-XXXXXX-Y'; // Tracking ID / Property ID.
hit += '&cid=555'; // Client ID.
/* Application opened */
function gacAppOpened() {
console.log('gacAppOpened');
hit += '&dp=%2Fslide-1'; // Page.
httpGetRequest(hit);
}
/* Slide-2 entered */
function gacSlide2() {
console.log('gacSlide2');
hit += '&dp=%2Fslide-2'; // Page.
httpGetRequest(hit);
}
function httpGetRequest( theUrl )
{
var req = new XMLHttpRequest();
req.open("POST", theUrl, true);
req.send(null);
}
}( jQuery ));
This is how I load the plugin (gaCustom.js) and my common JS file (app.js)
<script src="js/gaCustom.js"></script>
<script src="js/app.js"></script>
When trying to reach to my function from inside app.js, I got error (not a function)
goToDefault: function() { // loads first page of my app,
// a hit should be sent to GA about app started
...
gacAppOpened();
... // render template
},
So I am wrong somehow in defining the plugin and using it. I also tried few other attempts, but all of them failed.
I would appreciate to hear whether my approach is good or wrong and what to improve as I am a newbie and would like to do this correctly.
Related
I've been using Google Web Designer for a few months and I have a question. I don't know if it's possible to do in GWD:
I want the index.html file to load a different random page, choosing between 3 pages. When you hit reload, it should load another random page, and so on. The pages don't need to appear in order. I'm trying to find out how this can be done but I had no success so far.
This can be accomplished with a custom JavaScript event handler.
The <gwd-doubleclick> element fires an adinitialized event before any content is displayed, which we can use to make sure our changes are applied before the user sees the first page. It also provides a .goToPage(n) method which we can use to switch pages. (goToPage has additional arguments that can be used to control animation between pages, but we can ignore those because we want the default behaviour of instantly jumping.)
Start by adding a new event handler.
target: document.body
event: Google Ad: Ad Initialized
action: Custom: Add Custom Action
configuration: a name of your choice (such as gwd.goToRandomPage), for the following code:
var pages = 3; // adjust as appropriate
var targetPage = Math.floor(Math.random() * pages);
event.target.goToPage(targetPage);
In code view you can see that this produces something like the following:
// This script block is auto-generated. Please do not edit!
gwd.actions.events.registerEventHandlers = function(event) {
gwd.actions.events.addHandler('document.body', 'adinitialized', gwd.goToRandomPage, false);
};
gwd.actions.events.deregisterEventHandlers = function(event) {
gwd.actions.events.removeHandler('document.body', 'adinitialized', gwd.goToRandomPage, false);
};
You could choose to skip the GWD UI and use the standard JavaScript event handling APIs to accomplish the same thing, with something along the lines of:
document.body.addEventListener('adinitialized', function() {
var pages = 3; // adjust as appropriate
var targetPage = Math.floor(Math.random() * pages);
event.target.goToPage(targetPage);
});
However, you probably want to avoid this in general, because it will prevent GWD from handling things like element renaming automatically.
If you'd like to jump to one of a specific set of pages, instead of selecting from all pages, you could use an array of page IDs instead.
var pageIds = ['page1_1', 'page1_2'];
var targetPage = pageIds[Math.floor(Math.random() * pageIds.length)];
event.target.goToPage(targetPage);
For future reference, you can find most of the component APIs described in the documentation. Questions about GWD that do not involve code or are otherwise unsuitable for Stack Overflow should be asked on the GWD support forum instead.
I was asked to take a look at what should be a simple problem with one of our web pages for a small dashboard web app. This app just shows some basic state info for underlying backend apps which I work heavily on. The issues is as follows:
On a page where a user can input parameters and request to view a report with the given user input, a button invokes a JS function which opens a new page in the browser to show the rendered report. The code looks like this:
$('#btnShowReport').click(function () {
document.getElementById("Error").innerHTML = "";
var exists = CheckSession();
if (exists) {
window.open('<%=Url.Content("~/Reports/Launch.aspx?Report=Short&Area=1") %>');
}
});
The page that is then opened has the following code which is called from Page_Load:
rptViewer.ProcessingMode = ProcessingMode.Remote
rptViewer.AsyncRendering = True
rptViewer.ServerReport.Timeout = CInt(WebConfigurationManager.AppSettings("ReportTimeout")) * 60000
rptViewer.ServerReport.ReportServerUrl = New Uri(My.Settings.ReportURL)
rptViewer.ServerReport.ReportPath = "/" & My.Settings.ReportPath & "/" & Request("Report")
'Set the report to use the credentials from web.config
rptViewer.ServerReport.ReportServerCredentials = New SQLReportCredentials(My.Settings.ReportServerUser, My.Settings.ReportServerPassword, My.Settings.ReportServerDomain)
Dim myCredentials As New Microsoft.Reporting.WebForms.DataSourceCredentials
myCredentials.Name = My.Settings.ReportDataSource
myCredentials.UserId = My.Settings.DatabaseUser
myCredentials.Password = My.Settings.DatabasePassword
rptViewer.ServerReport.SetDataSourceCredentials(New Microsoft.Reporting.WebForms.DataSourceCredentials(0) {myCredentials})
rptViewer.ServerReport.SetParameters(parameters)
rptViewer.ServerReport.Refresh()
I have omitted some code which builds up the parameters for the report, but I doubt any of that is relevant.
The problem is that, when the user clicks the show report button, and this new page opens up, depending on the types of parameters they use the report could take quite some time to render, and in the mean time, the original page becomes completely unresponsive. The moment the report page actually renders, the main page begins functioning again. Where should I start (google keywords, ReportViewer properties, etc) if I want to fix this behavior such that the other page can load asynchronously without affecting the main page?
Edit -
I tried doing the follow, which was in a linked answer in a comment here:
$.ajax({
context: document.body,
async: true, //NOTE THIS
success: function () {
window.open(Address);
}
});
this replaced the window.open call. This seems to work, but when I check out the documentation, trying to understand what this is doing I found this:
The .context property was deprecated in jQuery 1.10 and is only maintained to the extent needed for supporting .live() in the jQuery Migrate plugin. It may be removed without notice in a future version.
I removed the context property entirely and it didnt seem to affect the code at all... Is it ok to use this ajax call in this way to open up the other window, or is there a better approach?
Using a timeout should open the window without blocking your main page
$('#btnShowReport').click(function () {
document.getElementById("Error").innerHTML = "";
var exists = CheckSession();
if (exists) {
setTimeout(function() {
window.open('<%=Url.Content("~/Reports/Launch.aspx?Report=Short&Area=1") %>');
}, 0);
}
});
This is a long shot, but have you tried opening the window with a blank URL first, and subsequently changing the location?
$("#btnShowReport").click(function(){
If (CheckSession()) {
var pop = window.open ('', 'showReport');
pop = window.open ('<%=Url.Content("~/Reports/Launch.aspx?Report=Short&Area=1") %>', 'showReport');
}
})
use
`$('#btnShowReport').click(function () {
document.getElementById("Error").innerHTML = "";
var exists = CheckSession();
if (exists) {
window.location.href='<%=Url.Content("~/Reports/Launch.aspx?Report=Short&Area=1") %>';
}
});`
it will work.
I have built an app using titanium alloy
index.js
// Use the Alloy.Globals.Facebook namespace to make Facebook module API calls
var facebookModule = Alloy.Globals.Facebook;
//set facebook app id
facebookModule.appid = Ti.App.Properties.getString("ti.facebook.appid");
//set permissions i.e what data I want
facebookModule.permissions = ['user_friends','user_photos'];
// Do not force a facebook html popover but use the native dialog if possible
facebookModule.forceDialogAuth = false;
//invoke method onto button from module
$.fbButton.style = facebookModule.BUTTON_STYLE_WIDE;
$.index.open();
In my index.js controller I have this segment of code, it executes and I am presented with a log in screen.
I then fall into 2 problems:
1) "FB Session: Should only be used from a single thread"
2) I am unable to get the access token.
Not sure how to resolve both as the inbuilt login function has it's own event handler.
Cheers
Like you said, the inbuilt login function does have it's own handler.. so you should listen for event changes, something like this:
facebookModule.addEventListener('login', function(e) {
if (e.success) {
Ti.App.Properties.setString('face_token', facebookModule.getAccessToken());
// DO SOMETHING WITH THE TOKEN - open new window, auth the user...
}
});
If you try to get the access token BEFORE the login event is fired, you'll end up bad.
Now about the single thread thing.. I did run into this a while back.. I'm not sure exactly what I did to solve it, but I think it might be related to opening multiple windows or event allowing more than one call to the facebook API. Try to check if you are closing your windows and if the login function is being called more than once.
Let me know if that works for you. Good luck.
In my Phonegap Android app, I have the following Javascript code:
function onDeviceready()
{
window.plugins.webintent.getUri(function(url)
{
alert("WebIntent Fired Up! URL is " + url);
if (url.substring(0, 37) === "https://xxxxxxx.com/confirmation.html")
{
alert("intent matched!");
var params = url.substr(url.indexOf("?") + 1);
params = params.split("&");
var verificationData = params[0].split("=");
var emailData = params[1].split("=");
launchLinkEmail = emailData[1];
launchLinkVerification = verificationData[1];
alert("verification is " + launchLinkVerification);
alert("email is " + launchLinkEmail);
}
});
}
$(document).ready(function() {
document.addEventListener('deviceready', onDeviceready, true);
});
The problem is that the variables launchLinkVerification and launchLinkEmail seem to get set after the page is loaded and the Javascript is finishing up, and so their value is empty when I try to call it anywhere that I want to use them. The alerts always display the information I want, but if I try to display them anywhere in my HTML pages, or set conditionals based on their value, neither work.
On the other hand, it seems that if I use window.plugins.webintent.getUri(function(url) anywhere other than onDeviceready it sometimes doesn't execute at all (or at least not under conditions that I can predict or understand), and again the variables don't get set.
Ultmately, what I want to do is:
Get the data from the URL that WebIntent captures.
If the data from WebIntent matches certain criteria, then switch to another page using window.location = confirmation.html
Fill two fields on the form on confirmation.html with the two variables I got from the URL that WebIntent picked up.
How do I get the data from the Webintent call, switch pages depending on what that data is, and then use that data on the new page?
I haven't used the WebIntent plugin specifically, but if I understand your description correctly, I think you're running into a problem where you're running some JavaScript in the head or maybe in the body to configure the page the way you want it. But that code is dependent upon what happens in your onDeviceready(). The call to onDeviceready() is going to be made asynchronously at anytime PhoneGap feels it is ready. Usually it is called quickly, but quickly is a relative term.
What you likely need is someway for this async code to then trigger the code you want. JQuery provides the $.Deferred() object which you might find helpful. You can setup a Deferred, you add your other code in with Deferred.done(), and when it runs onDeviceready() resolves the object which then runs the callbacks.
http://api.jquery.com/jQuery.Deferred/
I've used this to allow something like onDeviceready() to trigger a series of other behaviors in my application which I may not have wanted to structure into one big function.
So I'm making a Safari extension for my own personal use, and it's not working at all.
I'm trying to skip adf.ly and go directly to the website. But it's not doing anything at all.
I've tried alerting the current URL and the supposed new URL, and they aren't even displaying either.
Global.html
<!DOCTYPE html>
<script type='application/javascript'>
// Skip Adf.ly
// Made by Austen Patterson
// For Safari
//(C) Copyright 2013 Austen Patterson.
safari.application.addEventListener("start", performCommand, true);
safari.application.addEventListener("validate", validateCommand, true);
// Function to perform when event is received
function performCommand(event) {
// Make sure event comes from the button
if (event.command == "skip") {
var url = this.activeBrowserWindow.activeTab.url;
var newurl = url.replace(/http:\/\/adf\.ly\/(\d+)\//, '');
location.href(newurl);
window.open(newurl,"_self");
return;
}
}
</script>
and here is my extension builder settings.
You can't use alert from the global page. You can use console.debug, though, so that should help.
The bigger issue though is that you're treating the global page as though it has access to the page you're trying to modify via the window object. It doesn't work that way. location.href doesn't point to anything and window.open will probably not work from the global scope. (These are both leaky globals, which is something you want to avoid.) I haven't tested it, but something like this should work:
safari.application.addEventListener("beforeNavigate", function adflyChecker(event) {
var url = event.url.replace(/http:\/\/adf\.ly\/(\d+)\//, '');
safari.application.activeBrowserWindow.activeTab.url = url;
}, true);
This has the advantage of working on navigate and not requiring you to manually click the button. If you configure your extension to only apply to adf.ly URLs, then you can be sure that your code only fires when it's appropriate.
More information about the architecture of Safari extensions is available in the docs.