Multiple Tracking onclick link of omniture's s.tl(), Cant figure out - javascript

I am using a omniture jasavscript for Site Catalyst.
In which, I am populating the required variables onclick of a link.
But the problem is I get a multiple (2) tracking on a single click, which is not the ideal behaviour. in these 2 tracking, The FIrst one I get is the old one and right after that I get the second latest tracking.
It seems like it is using the cache memory.
UPDATE
I tried reinitializing the object by using var s = {}; before and after the use of s.tl('this','e','',null);
But it didn't worked
Could someone suggest how it can be rectified.

Without seeing any code I can only speculate, but my guess is the additional hit is from SiteCatalyst's auto-link tracking - either an exit link because the target URL is not listed in linkInternalFilters, or a download link because the target URL ends with something listed in linkDownloadFileTypes.
I suspect, given the 'e' argument of your s.tl() example, that the link is an exit link. So on that note.. perhaps the solution here is to piggyback off the auto-exit-link tracking, instead of making your own s.tl() call. Adobe has a plugin called exitLinkHandler that will let you trigger additional variables whenever the auto-exit-link tracking occurs.
Here is the plugin:
/*
* Plugin: exitLinkHandler 0.5 - identify and report exit links
*/
s.exitLinkHandler=new Function("p",""
+"var s=this,h=s.p_gh(),n='linkInternalFilters',i,t;if(!h||(s.linkTyp"
+"e&&(h||s.linkName)))return '';i=h.indexOf('?');t=s[n];s[n]=p?p:t;h="
+"s.linkLeaveQueryString||i<0?h:h.substring(0,i);if(s.lt(h)=='e')s.li"
+"nkType='e';else h='';s[n]=t;return h;");
Within your s_doPlugins function, add the following:
s.url = s.exitLinkHandler();
if (s.url) {
// pop your variables here. Don't forget to pop `linkTrackVars` and `linkTrackEvents`, same as you would have done before
}
Now, this will make your additional variables pop on any exit link triggered. If you want it to only trigger on certain URL matches, or only on a specific match, you can do this several ways, depending on your needs:
If you only need to do a general substring match, you can pass some
or all of the target URL as the first argument for
s.exitLinkHandler() and it will match the passed argument against
the target URL.
If this isn't good enough, within the if(s.url) condition, you can
perform your own matching (e.g. regex matching) against the target
URL using s.url.
If you need to target by some DOM attribute of the link, within the
condition, s.eo is an object reference to the link that was
clicked, so you can write your own conditions around that.

Option 1
Omniture does not track links with # as exit links so you can do something like:
Search
<script>
(function (){
'use strict';
var links = document.querySelectorAll('.prepended-with-hash-for-tracking');
var track = function(e) {
e.preventDefault();
var link = e.currentTarget;
var url = link.href;
var trackingMessage = link.getAttribute('data-track-msg');
// Remove the hash.
if (url[0] === '#') {
url = url.substr(1);
}
// Track in omniture.
var s = s_gi('InsertYourRSID');
s.tl(link, 'o', trackingMessage, null, function(){
window.location.href = url;
});
};
for (var i = 0, len = links.length; i < len; i++) {
links[i].addEventListener('click', track, false);
}
})();
</script>
Option 2
Another work-a-round is to set s.linkLeaveQueryString = true; and then append the url with a query parameter containing your domain name which matches a string in s.linkInternalFilters. e.g. Share
Option 3
Disable omniture's default external link tracking by setting s.trackExternalLinks=false; and then you can handle all external links with an event handler that calls s.tl() with JavaScript similar to option 1.
I would recommend option 3.

Related

How to invoke javascript function when # is present in URL

I am trying to call JavaScript function when # is present in URL. I know normal behavior is to navigate / scroll to the specific tag. But could not find how to invoke a JavaScript function.
The below example is close but not solving my problem.
What is the meaning of # in URL and how can I use that?
You might be able to leverage the hashchange event to trigger the function, assuming you don't just want to keep polling the location to see if it changes.
DOCS: https://developer.mozilla.org/en-US/docs/Web/API/Window/hashchange_event
This code snippet will add the listener to the current page, then manipulate the hash and fire the function, displaying the new hash value. You could call any function here.
window.addEventListener('hashchange', function() {
alert(location.hash);
});
window.location += "#test";
var hash = window.location.hash;
if(hash){
// do something
}
<script>
if (window.location.href.includes('#')) {
// run your code here
}
</script>
use a location.hash function will solve your problem
var hash = window.location.hash.replace(/#/g, '');
if(hash){
// found a hash
console.log("heyy I found a hash")'
}
else{
// did not find a hash
console.log("Uh oh")
/*
try using :
window.location = window.location + '#' + "some random variable"
to create a new URL and every time the page loads find the hash and
display the wanted data.
*/
}
PS: this only works if your URL is like example.com/#xyz
then it will give you xyz as a console output. This may sound
vague but if you do this you may get a Idea

Quill link handler not working

I'm trying to write a custom handler for the link input value. In case the user inputs a link that does not have a custom protocol, I wish to prepend a http: before the input value. That's because if link value lacks http:, link is not interpreted and about:blank is shown intead. (https://github.com/quilljs/quill/issues/1268#issuecomment-272959998)
Here's what I've written (similar to the official example here):
toolbar.addHandler("link", function sanitizeLinkInput(linkValueInput) {
console.log(linkValueInput); // debugging
if (linkValueInput === "")
this.quill.format(false);
// do nothing, since it implies user has just clicked the icon
// for link, hasn't entered url yet
else if (linkValueInput == true);
// do nothing, since this implies user's already using a custom protocol
else if (/^\w+:/.test(linkValueInput));
else if (!/^https?:/.test(linkValueInput)) {
linkValueInput = "http:" + linkValueInput;
this.quill.format("link", linkValueInput);
}
});
Every time the user clicks the link icon, nothing happens and true is logged to the console. I actually wished this handler to be executed when person clicks "save" on the tooltip that's shown after pressing the link icon.
Any idea how to do this? Hints or suggestions are also appreciated.
Thanks!
congregating all the information
The snow theme itself uses the toolbar's addHandler to show a tooltip and so it is impossible to use the addHandler method to achieve what we wish to.
So, instead we can do the following:
var Link = Quill.import('formats/link');
var builtInFunc = Link.sanitize;
Link.sanitize = function customSanitizeLinkInput(linkValueInput) {
var val = linkValueInput;
// do nothing, since this implies user's already using a custom protocol
if (/^\w+:/.test(val));
else if (!/^https?:/.test(val))
val = "http:" + val;
return builtInFunc.call(this, val); // retain the built-in logic
};
this method doesn't hook onto handlers but instead modifies the built-in sanitisation logic itself. We have also retained the original behavior of the sanitisation so that doesn't modify the editor's original behavior.
Alternatively, we could actually hook onto the save button of the tooltip, using this code. But it is too long a method compared to the one above.
As far as I can tell, the handling of creating and updating links is a bit distributed in Quill's sources. The default Snow theme handles editing links to some extent: it tracks the user selection and last selected link internally. Because of this I do not think that it is possible to achieve what you want currently in Quill using only a custom handler.
You may want to open an issue to report this, the authors might be willing to add such a handler.
In the meantime I came up with a way to update the link by simply listening for events causing the edit tooltip to close. There are some complications, because a link can be edited and the theme then relies on its internal tracking to update it. However, all in all I think that this solution is not too bad. You might want to add some error checking here and there, but overall it seems to work nicely and do what you want it do to. I have created a Fiddle demonstrating this. For completeness, I have included it here as a code snippet too.
var quill = new Quill('#editor', {
modules: {
toolbar: true
},
theme: 'snow'
}),
editor = document.getElementById('editor'),
lastLinkRange = null;
/**
* Add protocol to link if it is missing. Considers the current selection in Quill.
*/
function updateLink() {
var selection = quill.getSelection(),
selectionChanged = false;
if (selection === null) {
var tooltip = quill.theme.tooltip;
if (tooltip.hasOwnProperty('linkRange')) {
// user started to edit a link
lastLinkRange = tooltip.linkRange;
return;
} else {
// user finished editing a link
var format = quill.getFormat(lastLinkRange),
link = format.link;
quill.setSelection(lastLinkRange.index, lastLinkRange.length, 'silent');
selectionChanged = true;
}
} else {
var format = quill.getFormat();
if (!format.hasOwnProperty('link')) {
return; // not a link after all
}
var link = format.link;
}
// add protocol if not there yet
if (!/^https?:/.test(link)) {
link = 'http:' + link;
quill.format('link', link);
// reset selection if we changed it
if (selectionChanged) {
if (selection === null) {
quill.setSelection(selection, 0, 'silent');
} else {
quill.setSelection(selection.index, selection.length, 'silent');
}
}
}
}
// listen for clicking 'save' button
editor.addEventListener('click', function(event) {
// only respond to clicks on link save action
if (event.target === editor.querySelector('.ql-tooltip[data-mode="link"] .ql-action')) {
updateLink();
}
});
// listen for 'enter' button to save URL
editor.addEventListener('keydown', function(event) {
// only respond to clicks on link save action
var key = (event.which || event.keyCode);
if (key === 13 && event.target === editor.querySelector('.ql-tooltip[data-mode="link"] input')) {
updateLink();
}
});
<link href="https://cdn.quilljs.com/1.1.10/quill.snow.css" rel="stylesheet" />
<script src="https://cdn.quilljs.com/1.1.10/quill.min.js"></script>
<div id="editor"></div>
Let me know if you have any questions.
The toolbar handler just calls your given function when the button in the toolbar is clicked. The value passed in depends on the status of that format in the user's selection. So if the user has highlighted just plain text, and clicked the link button, you will get false. If the user highlighted the link, you will get the value of the link, which is by default the url. This is explained with an example here: http://quilljs.com/docs/modules/toolbar/#handlers.
The snow theme uses toolbar's addHandler itself to show a tooltip and it looks like you are trying to hook into this, which is not possible at the moment.
It looks like what you are really trying to do is control the sanitization logic of a link. Sanitization exists at a lower level in Quill since there are many ways to insert a link, for example from the tooltip UI, from paste, from the different APIs, and more. So to cover them all the logic is in the link format itself. An example of custom formats of links specifically is covered in http://quilljs.com/guides/cloning-medium-with-parchment/#links. You can also just modify Quill's own sanitize method but this is not recommended as it is not documented nor covered by semver.
let Link = Quill.import('formats/link');
Link.sanitize = function(value) {
return 'customsanitizedvalue';
}
after spending half an hour
found this solution
htmlEditorModuleConfig = {
toolbar: [
['link']
],
bounds: document.body
}
Add 'bounds: document.body' in configuration
I have to do same exact thing,(validate url before sending to server) so I end up with some thing like this.
const editor = new DOMParser().parseFromString(value,
'text/html');
const body = qlEditor.getElementsByTagName('body');
const data = document.createElement('div');
data.innerHTML = body[0].innerHTML;
Array.from(data.querySelectorAll('a')).forEach((ele) => {
let href = ele.getAttribute('href');
if (!href.includes('http') && !href.includes('https')) {
href = `https://${href}`;
ele.setAttribute('href', href);
}
});
body[0].innerHTML = data.innerHTML;
Maybe this is an old question but this is the way I make it work.
First, it whitelist other custom protocols to be accepted as valid ones.
Then, we run the sanitize method that is already included on the Quill core, and based on the custom protocols list it will return the URL or about:blank.
Then, if this is a about:blank is because it did not pass the sanitization method. If we get the URL then we verify whether or not it has a protocol from the list and if not, then we append http:// and in that way we do not get relative URL or blank unless it is not being whitelisted:
https://your-site.com/www.apple.com
about:blank
Hope it helps anyone else having this same issue.
const Link = Quill.import('formats/link')
// Override the existing property on the Quill global object and add custom protocols
Link.PROTOCOL_WHITELIST = ['http', 'https', 'mailto', 'tel', 'radar', 'rdar', 'smb', 'sms']
class CustomLinkSanitizer extends Link {
static sanitize(url) {
// Run default sanitize method from Quill
const sanitizedUrl = super.sanitize(url)
// Not whitelisted URL based on protocol so, let's return `blank`
if (!sanitizedUrl || sanitizedUrl === 'about:blank') return sanitizedUrl
// Verify if the URL already have a whitelisted protocol
const hasWhitelistedProtocol = this.PROTOCOL_WHITELIST.some(function(protocol) {
return sanitizedUrl.startsWith(protocol)
})
if (hasWhitelistedProtocol) return sanitizedUrl
// if not, then append only 'http' to not to be a relative URL
return `http://${sanitizedUrl}`
}
}
Quill.register(CustomLinkSanitizer, true)

How to determine the cause of a HashChangeEvent

How to determine if a HashChangeEvent was triggered by an user action in the page (click on a link, button, or something like), or manually input in the address bar?
I think your best bet is to create some kind of wrapper that allows you to change the window.location.hash attribute, and call it from any elements that you want to be tracked. I have created an example on Plunker to demonstrate my idea of how that would be done. The example is pretty rudimentary, however. I think it conveys the point of what you're trying to do though.
I'll also put the example here, but it's not functional obviously. Let me know if you think this is going to cover your use case. I can tweak it if needed.
(function($) {
'use strict';
//Create a route function on the jQuery object
//that we can use anywhere.
/**
* Wraps the setter for window.location.hash
* and tracks who called it.
*
* #param {Element} who The element that called route.
* #param {string} hash The hash to set.
*/
$.route = function(who, hash) {
$.route.who = who;
window.location.hash = hash;
};
})(jQuery);
The code below shows how you can use the $.route function to track which element changed the window.location.hash value.
(function($) {
'use strict';
window.addEventListener('hashchange', function() {
if ($.route.who) {
//We know this was one of our tracked elements.
alert(`Tag Name "${$.route.who.prop('tagName')}" triggered hash change.`);
} else {
//We'll assume that this wasn't being tracked, and therefore
//is most likely to be caused by user input.
alert('We could not track what triggered "hashchange".');
}
//Don't forget to reset this so that if an untracked input triggered this
//it doesn't appear that it was tracked.
$.route.who = null;
});
$(function() {
$('.hash-change').click(function(e) {
//Do some internal routing action that can track the caller.
var $this = $(this);
//Get the hash to set to the URL.
var href = $this.attr('href') || $this.data('href');
//Use our internal routing action to track the caller.
$.route($this, href);
//Prevent the default action of those hyperlinks by returning false.
return false;
});
});
})(jQuery);
The HTML that I used in my example looks like this. Each one has the class hash-change. Elements that natively support href use it, others that don't use the dataset for the href.
<a class="hash-change" href="home">Home</a>
<a class="hash-change" href="about">About</a>
<input type="button" class="hash-change" data-href="contact" value="Contact" />
Those elements will be tracked and will use the $.route function to change the hash value. Anything that doesn't use the $.route function will not set the $.route.who value, and therefore, you can assume it was changed from some source, such as the user manually changing the hash.
Ultimately, whatever solution you implement will have to be a wrapper around existing functionality. Take a look at the Plunker example for a live demo.

Javascript, determine which button was selected in a function, similar to (id)sender in iOS?

I'm taking a Javascript class and was wondering if there was a way to tell which button was selected when a function is called. I basically have a method like this:
function sendRequest()
{
var url = "http://classwebsite/bookmarks.php";
url += "?userid=crystal";
var transmission = document.getElementById("transmission").value;
url += "&response=" + transmission;
var callback = {success:handleResponse,
failure:handleFailure,
timeout:5000
};
var transaction = YAHOO.util.Connect.asyncRequest("GET", url, callback, null);
}
This method gets called when a button is pressed. It basically gets back the prof's response in the appropriate JSON, XML, etc format and displays it. I want to add an "add" feature to add new rows to the table. That's done by calling the same URL in the above method and just manually putting this in the address bar:
http://classwebsite/bookmarks.php?userid=crystal&action=add&name=yahoo&url=yahoo.com&desc=Yahoo+website
In this scenario, if I had another button called "Add" to add in fields from a form, would I call the same sendRequest() method, and modify the url accordingly? If so, how do I know which button was pressed if both the "List" button and "Add" button would be tied to the same event handler.
Or is it a better design to have another method, that handles addRequest() and just adds fields from the form? Thanks.
If you did use the Yahoo utils like they are supposed to be used (i.e. via YAHOO.util.Event.addListener()), then your button is referenced by this.
See Automatic Scope Correction in the YUI docs.
In addition, please encode URL parameters correctly before you use them.
var transmission = document.getElementById("transmission").value,
url = "http://classwebsite/bookmarks.php"
+ "?userid=crystal"
+ "&response=" + encodeURIComponent(transmission); // <- !!
You should be able to modify the parameters of your javascript function to see the sender.
There is also a hidden array called arguments, that will let you look at what parameters are available to a function, in case you are ever curious.
function sendRequest(sender, args) {
//sender is your clicked button
var url = "http://classwebsite/bookmarks.php";
url += "?userid=crystal";
var transmission = document.getElementById("transmission").value;
url += "&response=" + transmission;
var callback = {success:handleResponse,
failure:handleFailure,
timeout:5000
};
var transaction = YAHOO.util.Connect.asyncRequest("GET", url, callback, null);
}
If a button is pressed then an event should be passed to the function. The event object contains the target of the click among other things.
function sendRequest(e) {
var target;
if(!e) {
e = window.event;
}
// the button clicked can now be accessed as
// we use the ternary because IE uses a different property
target = e.target ? e.target : e.srcElement;
}
Youll note a couple if statements in there... this is because IE differs a bit form the standard. However, i see youre using a Yahoo lib for some of your js. I imagine if you are to use the facilities of this library to bind your events it would also normalize the event object passed in to your callbacks so you wouldnt have to manually create xbrowser accommodations.

How to run a javascript function using the # in the url?

hi this all started when i ran a function (lets call it loadround) that altered the innerHTML of an iframe. now once loadframe was loaded there were links in the iframe that once clicked would change the iframe page. the only problem is when i click the back button the loadround page was gone. i've thought about this numerous times to no avail. so i tried this code.
loadround
then
function loadround(a,b){
window.location.hash = "#loadround('"+a+"','"+b+"')";
var code = "<(h2)>"+a+"</(h2)><(h2)>"+b+"</(h2)>"
var iFrame = document.getElementById('iframe');
var iFrameBody;
iFrameBody = iFrame.contentDocument.getElementsByTagName('body')[0]
iFrameBody.innerHTML = code;
}
(the brackets in the h2 are intentional)
then i would try to reload the function by possibly an onload function but for now i was testing with a simple href as followed.
function check(){
var func = location.hash.replace(/#/, '')
void(func);
}
check
unfortunately the check code doesn't work and im almost certain there is an easier way of doing this. i tried changing the src of the iframe instead of the innerhtml and there was the same problem. thanks in advance
The modern browsers are starting to support the event window.onhashchange
In the meantime you can use the workaround proposed by Lekensteyn or maybe you can find something useful here: JavaScript/jQuery - onhashchange event workaround
You are misunderstanding the function void, which just make sure the return value is undefined. That prevents the browser from navigating away when you put it in a link. You can test that yourself by pasting the next addresses in your browser:
javascript:1 // note: return value 1, browser will print "1" on screen
javascript:void(1) // note: undefined return value, browser won't navigate away
It's strongly discouraged to execute the hash part as Javascript, as it's vulnerable to XSS without proper validating it. You should watch the hash part, and on modification, do something.
An example; watch every 50 milliseconds for modifications in the hash part, and insert in a element with ID targetElement an heading with the hash part. If the hash part is not valid, replace the current entry with home.
var oldHash = '';
function watchHash(){
// strip the first character (#) from location.hash
var newHash = location.hash.substr(1);
if (oldHash != newHash) {
// assume that the parameter are alphanumeric characters or digits
var validated = newHash.match(/^(\w+)$/);
// make sure the hash is valid
if (validated) {
// usually, you would do a HTTP request and use the parameter
var code = "<h1>" + validated[1] + "</h1>";
var element = document.getElementById("targetElement");
element.innerHTML = code;
} else {
// invalid hash, redirect to #home, without creating a new history entry
location.replace("#home");
}
// and set the new state
oldHash = newHash;
}
}
// periodically (every 50 ms) watch for modification in the hash part
setInterval(watchHash, 50);
HTML code:
Home
About Me
Contact
<div id="targetElement">
<!-- HTML will be inserted here -->
</div>

Categories