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.
Related
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.
I have a single page website and would like to achieve the following:
back button working as if it was a normal website
and instead of say,
www.mysite.com/index.php?p=#this-is-a-great-product
I'd like to have this url
www.mysite.com/this-is-a-great-product
while still having back button working properly.
Regarding 1.) I use the following code ive found which works great:
<!-- Getting BackButton to work properly -->
<script type="text/javascript">
var times = 0;
function doclick() {
times++;
}
function doclick() {
times++;
location.hash = times;
}
window.onhashchange = function() {
if (location.hash.length > 0) {
times = parseInt(location.hash.replace('#',''),10);
} else {
times = 0;
}
}
</script>
…but of course it just changes any anchors to /#1, then /#2 and so forth ro get the backbutton to work. But as I'm not a programmer I don't know how to change it… :(
Regarding 2.) i can add in htaccess this:
>RewriteEngine On
>RewriteRule ^([^/.]+)/?$ /index.php?page=$1
and this changes /index.php?p=products to /products.
So how do I change the above code (under 1.) so it doesn't change all anchors to #1, #2, etc. but instead references / uses the urls I achieved under 2, like
www.mysite.com/this-is-a-great-product
And (probably a very dumb question, but a very important one) -given I use only the new url links on my site- is there any danger that this still might result in duplicate content in any way?
Regarding this, should I (for that reason or any other) sefreferential my single page index.php to itself using rel canonical link=index.php?
Thanks so much in advance!
As mentioned, you will want to use the HTML5 History API. Please note, this API is relatively new and therefore browser support is a concern. At the time of writing, approximately 71% of global Internet users have support for it (see http://caniuse.com/#feat=history for browser support information). Therefore, you will want to ensure you have a fall-back solution for this. You will likely want to use the older #! solution that was popular before the HTML 5 History API was adopted.
If you use the history API to replace, for example, example.com/#!settings with example.com/settings and a user bookmarks that nicer URL, then when they go to visit it, their browser will make a request to the server for /settings (which doesn't actually exist in the web server's context). Therefore, you will need to make sure your web server has some redirection rules (i.e. RewriteEngine) such that it can take the pretty URLs and redirect them to the #! version (and then if the user's browser supports the history API it can replace that with the nice URL).
If you aren't very comfortable programming yourself, I'd recommend using a JavaScript library that does a lot of the work for you. I did some quick searching and discovered the following, though there might be better ones out there: https://github.com/browserstate/history.js
Basically i have created a small prototype on jsfiddle which tracks all the urls accessed via ajax calls.
Also contains navigation to access links back and forth .
How It Actually Works:
I have created a global array called history, which keeps track of all urls accessed via ajax in sequence.
also there a global index defined to keep track of the url being accessed when navigating back and forth the links in history array.
There is History section at the bottom of the jsfiddle, which shows the sequence in which the links are accessed by capturing the link names and posting them in the order in which they were accessed.
JS Code:
$(function () {
var history = [];
var index = 0;
$('.links').on('click', function () {
$('#history').append($(this).text());
var address = $(this).attr('data-ref');
index += 1;
history[index] = address;
$('.links').attr('disabled', 'disabled');
loadExternalPage(address);
console.log('list:' + history);
});
$('#back').on('click', function () {
console.log(index);
index -= 1;
console.log(index);
console.log(history[index]);
loadExternalPage(history[index]);
});
$('#forward').on('click', function () {
console.log(index);
index += 1;
console.log(index);
console.log(history[index]);
loadExternalPage(history[index]);
});
var loadExternalPage = function (address) {
console.log(history[index]);
$('#result-section').load(address, function () {
console.log('data-loaded');
$('.links').removeAttr('disabled');
});
};
});
Live Demo # JSFiddle:http://jsfiddle.net/dreamweiver/dpwmcu0b/8/
Note: This solution is far from being perfect, so dont consider it as final solution but rather use it as a base to build upon
On using BACK and FORWARD functions in the browser top-left button:
In principle, there is no great problem with this as long as you work with the existing storage object (a stack) for previously visited web pages on your browser. This object is the history object and you can see what is in it anytime by right-clicking and selecting "Inspect", then selecting the "Console" tab, then enter window.history and enter.
Check out the Browser Object Model (BOM) section of Pro Java For Web Developers (Frisbee) for the background to the history object. (Just a few pages, an easy read, don't worry.) Just remember that in this process you are storing the new page that you move to, not the old page that you are leaving !
For a simple SPA example, look at this example. codepen.io/tamjk/pen/NWxWOxL
In regard to the URL, the method that the history object uses to load a new page state into the history stack, i.e. pushState(...), has an optional third parameter for associating a dummy URL for each web page that is stored.
Personally, when I first sorted out the BACK & FORWARD functions, I did not use dummy URLs as the browser was being confused by them and I had enough to do sorting out the history sequence using just the first two parameters, i.e.
the state object - a JSON holding enough data to recreate the page stored
a title for the page I expect that you could also use a dummy URL but I will leave that to the student as an exercise, as they say.
But you can add the URL of the new page if you want to.
In the example above, for the state object I just used the IDs of the page's nav link and its content element.
For the title, I programmatically changed the HTML's page title element with each change of page. I did this after noticing that the browser listed the previous pages according to the title element in the HTML code.
Unfortunately, this title does not show up on CodePen when you right-click on the browser BACK and FORWARD buttons due to CodePen's system not allowing it. But it will show on your own sites.
It's important that whatever method you use to store current web page states when using the navbar links to navigate, you DO NOT ADD page states to the browser history when you arrive at them using BACK or FORWARD buttons. Otherwise your history stack will have repetitions of entries going back and deletion of entries going forward.
In the CodePen, this was achieved by having the addToHistory(..) function separate to and outside the scope of the switchPage(...) function. This allows you use of the switchPage function in both normal navbar navigation and browser BACK/FORWARD navigation. The third parameter of switchPage(...) is a boolean indicating if the page is to be stored in history or not.
Anyway, this is just something to get you started.
I am trying to track user interaction on a website that I manage myself. By tracking I mean, I want to track which button or widget the user pressed and when and also how much time a user spent and etc. Before I dive into coding something up on Javascript, I just to get an idea what are best options to do such things and possible pitfalls.
It's been some time since this question was posted, but I've been working on a simple JavaScript module to do just this.
Rather than using images, it captures event data from user-specified HTML element(s) along side some basic information about the site visitor's browser configuration. The data is then sent to a specified server endpoint using an XHR triggered on the beforeunload event.
Here's a link to the GitHub project and an example page
Regarding the code, here's an example of what the HTML would look like:
<!DOCTYPE html>
<html>
<head>
<title>Interaction Tracker Example</title>
</head>
<body>
<div class="someElement"></div>
<div class="someOtherElement"></div>
<div class="conversion"></div>
<script src="interactor.min.js" type="application/javascript"></script>
<script>
// An example instantiation with custom arguments
var interactions = new Interactor({
interactions : true,
interactionElement : "someElement someOtherElement",
interactionEvents : ["mousedown"],
conversions : true,
conversionElement : "conversion",
conversionEvents : ["mouseup"],
endpoint : '/usage/interactions',
async : true
});
</script>
</body>
</html>
The architecture allows you to easily track multiple elements through multiple instantiations, allowing you to customize which endpoints different interactions are sent to. This allows for clean separation of any server-side pre-processing prior to saving the data to a database.
var elementsToTrack = [
{
element : "cssClass1",
events : ["mouseup", "touchend"],
endpoint : "/interactions/c1"
},
{
element : "cssClass2",
events : ["mouseup"],
endpoint : "/interactions/c2"
},
{
element : "cssClass3",
events : ["mouseup"],
endpoint : "/interactions/c3"
}
];
for (var i = 0; i < elementsToTrack.length; i++) {
var el = elementsToTrack[i];
new Interactor({
interactionElement : el.element,
interactionEvents : el.events,
endpoint : el.endpoint
});
}
Finally, it's very lightweight (about 5KB minified) and easily extendable to most needs.
If you don't need to return any value from server, ajax is a bit overhead - I would use image pings (creating image elements with script as source with any parameter you want to send)
For events, bind them to document and check event target (be aware - blur, focus and change do not bubble)
document.body.addListener(event, function() {
var i = new Image();
i.src = 'script.php?target=' + event.target;
}, false);
For time measurement, you could check time that passes between events on elements.
I would recommend looking into something like mixpanel. It's very simple to integrate and they provide you with the graphic tools to parse large amounts of data. The basic premise is similar to what you said. Fire asynchronous events on specific user interaction, passing along a set of options. You can also integrate it into your Python code, which makes it easy to track when server side actions take place. Example:
$("#my_button").click(function() {
// This sends us an event every time a user clicks the button
mixpanel.track("Button clicked");
});
You can explore the docs for yourself. https://mixpanel.com/docs/integration-libraries/javascript
Mixpanel is just one option, but the premise is the same for all. The thing you need to consider is managing that data after it's been collected. Companies like mixpanel provide a nice GUI to make it less of a headache.
Google Analytics provides a good Javascript library for this:
https://github.com/googleanalytics/autotrack
Of course, it expects you to use Google Analytics in your app, but it has a free version you can use. Check the comparison between their free and paid services.
I just started using SSE and wonder how I can make them more dynamic.
I'm using a Box to select users and an image and text changes corresponding to the username.
Now I want to check for user updates via SSE and want the user to be still selectable.
I tried to add the eventSource when I'm changing the <select> box:
function setSelected(elm) {
selectedName = elm.options[elm.selectedIndex].innerHTML;
var eSource = new EventSource("getState.php?passVar=" + selectedName);
eSource.onmessage = function(event) {
document.getElementById("stateText").innerHTML = event.data;
};
}
How can I reach my goal?
edit
I have now added the eventSource successfully (I had an issue with the source itself).
But when I now add another source, I have actually two sources running.
How can I remove the old one?
To remove the previous event source use the close() method. You're going to have to keep the reference to eSource around somehow to do this.
I am trying to start 3 applications from a browser by use of custom protocol names associated with these applications. This might look familiar to other threads started on stackoverflow, I believe that they do not help in resolving this issue so please dont close this thread just yet, it needs a different approach than those suggested in other threads.
example:
ts3server://a.b.c?property1=value1&property2=value2
...
...
to start these applications I would do
location.href = ts3server://a.b.c?property1=value1&property2=value2
location.href = ...
location.href = ...
which would work in FF but not in Chrome
I figured that it might by optimizing the number of writes when there will be effectively only the last change present.
So i did this:
function a ()
{
var apps = ['ts3server://...', 'anotherapp://...', '...'];
b(apps);
}
function b (apps)
{
if (apps.length == 0) return;
location.href = apps[0]; alert(apps[0]);
setTimeout(function (rest) {return function () {b(rest);};} (apps.slice(1)), 1);
}
But it didn't solve my problem (actually only the first location.href assignment is taken into account and even though the other calls happen long enough after the first one (thanks to changing the timeout delay to lets say 10000) the applications do not get started (the alerts are displayed).
If I try accessing each of the URIs separately the apps get started (first I call location.href = uri1 by clicking on one button, then I call location.href = uri2 by clicking again on another button).
Replacing:
location.href = ...
with:
var form = document.createElement('form');
form.action = ...
document.body.appendChild(form);
form.submit();
does not help either, nor does:
var frame = document.createElement('iframe');
frame.src = ...
document.body.appendChild(frame);
Is it possible to do what I am trying to do? How would it be done?
EDIT:
a reworded summary
i want to start MULTIPLE applications after one click on a link or a button like element. I want to achieve that with starting applications associated to custom protocols ... i would hold a list of links (in each link there is one protocol used) and i would try to do "location.src = link" for all items of the list. Which when used with 'for' does optimize to assigning only once (the last value) so i make the function something like recursive function with delay (which eliminates the optimization and really forces 3 distinct calls of location.src = list[head] when the list gets sliced before each call so that all the links are taken into account and they are assigned to the location.src. This all works just fine in Mozilla Firefox, but in google, after the first assignment the rest of the assignments lose effect (they are probably performed but dont trigger the associated application launch))
Are you having trouble looping through the elements? if so try the for..in statement here
Or are you having trouble navigating? if so try window.location.assign(new_location);
[edit]
You can also use window.location = "...";
[edit]
Ok so I did some work, and here is what I got. in the example I open a random ace of spades link. which is a custom protocol. click here and then click on the "click me". The comments show where the JSFiddle debugger found errors.