Right implement dataLayer or not? - javascript

I need advice. Currently, i have website. There are bookmarks on main page without reload page (onclick). Normally I would not have a problem with it, but i can´t catch relevant data about bookmars like elementID, elementClasses etc (not possible change it).. i attached screen for better idea . Website has many language versions therefore is not possible use Click Text.
I suggest use this on every bookmark:
onclick="dataLayer.push({'event': 'name-of-bookmark'});"
Trigger -> custom event -> fire on: event name=name-of-bookmark
Tag -> UA - Event... -> fire on: bookmark-trigger
Is it right way or you have better solutions?

Am a google analytics expert. When it comes to GTM, the dataLayer is the best guy to trust on events.
Yes the syntax onclick="dataLayer.push({'event': 'name-of-bookmark'});"is correct and you can TRIGGER your event using that event

I always like to avoid inline javascript when I can, I believe it is possible to get what you want without using any dataLayer pushes and it will result in a cleaner implementation. The key is custom dataLayer value macros.
A Simple Example
Let's take the following html example that doesn't have any classes or ids.
<div>
<h2>My First Title</h2>
<img src="picture.png" />
</div>
<div>
<h2>My Second Title</h2>
<img src="picture.png" />
</div>
We want to track when someone clicks on the first link but there doesn't seem to be any default macro we can use to capture the link. Here's where the custom macro comes in
Create a new macro with the following settings:
Macro Name = "elementFirstSiblingInnerHTML"
Type = "DataLayer Variable"
Variable Name = "gtm.element.parentElement.firstElementChild.innerHTML"
You can then create a trigger with the following settings:
Trigger Name = "My First Title Click"
Choose Event = "Click"
Fire On {{elementFirstSiblingInnerHTML}} equal to "My First Title"
Viola, you now have a trigger for when someone clicks on the first link without any classes, ids etc. The macro works by looking at the element's parent's first child's innerHTML which is equal to "My First Title"; setting off the trigger.
This is just one example, but you pretty much have access to the whole DOM via the gtm.element DataLayer variable that gets set on a click. It's just centered around the clicked element.
Create your own dataLayer value macro
Here's an important tip. When developing a macro it's useful to be able to test it out in the web console. However, the console doesn't support the same dot notation as the GTM portal. So in order to develop in the console instead of
gtm.element.parentElement.firstElementChild.innerHTML
you would use (assuming the click event was the 8th event in the dataLayer)
dataLayer[7]["gtm.element"].parentElement.firstElementChild.innerHTML
If you provide me a link to the page you are referring to I could probably come up with a custom macro that would work in your situation. Also, here's a great blog on the subject as well. http://www.simoahava.com/analytics/macro-magic-google-tag-manager/ (item 14 in his list)

Related

EventListener cloning in userscript

I have this function:
function main() {
var bottomArea = document.getElementsByClassName("bottom-area");
for (var i = 0; i < bottomArea.length; i++) {
var showDialogLink = document.createElement("a");
showDialogLink.innerHTML = "link";
showDialogLink.onclick = function(){showSelect(this);return false;};
bottomArea[i].insertBefore(showDialogLink, bottomArea[i].childNodes[3]);
}
}
So far the code works just fine. When I click the newly created link, it calls showSelect(this) function just fine.
The problem is there is another userscript/browser extension (which I don't have access to - it's not mine), which basically clones whole another div in which 'bottom-area' div is nested. This is all right too, but the problem is that it doesn't clone my function trigger and those newly cloned instances (I'm not really sure what is their nature) of that link do no longer trigger showSelect(this) function. Only the first one created by my userscript does.
Is there some way in which I should add my function trigger on my link, that will stay even after cloning/copying?
EDIT: I'll just edit to show html tree:
This is at the beginning:
<div>
<div class="bottom-area"></div>
</div>
My userscript adds a link with an onclick eventlistener on the 'a' tag:
<div>
<div class="bottom-area"><a>link</a></div>
</div>
The other userscript basically clones it (there is a textarea inside the div and its value gets cloned too), but without the eventlistener, so clicking on the cloned links no longer triggers my function.
EDIT2: If it helps, the userscript I'm creating is a reddit userscript. I'm adding small functionality to commenting and adding a link right next to the 'reddiquette' link under the comment text field. That works with the pre-generated text field. However when I click 'reply' down the comment tree, the whole div together with text field, submit button and my link gets cloned under the comment I'm replying too, but my link no longer has the function trigger on itself.
The easiest solution may be to simply use HTML event attributes (instead of addEventListener), such as <a onclick="dostuff();">link</a>, because the attribute should be preserved during 'cloning'. See this fiddle (tested in Firefox 40) for an example.
Letting the code in the onclick attribute interact with your userscript may be be a little difficult because it runs in a different JavaScript environment. Luckily there's plenty of possible workarounds, depending on your exact needs.

Inline Editing But Instance Doesn't Exist

I have my own custom non-jQuery ajax which I use for programming web applications. I recently ran into problems with IE9 using TinyMCE, so am trying to switch to CKeditor
The editable text is being wrapped in a div, like so:
<div id='content'>
<div id='editable' contenteditable='true'>
page of inline text filled with ajax when links throughout the site are clicked
</div>
</div>
When I try to getData on the editable content using the examples in the documentation, I get an error.
I do this:
CKEDITOR.instances.editable.getData();
And get this:
Uncaught TypeError: Cannot call method 'getData' of undefined
So I figure that it doesn't know where the editor is in the dom... I've tried working through all editors to get the editor name, but that doesn't work-- no name appears to be found.
I've tried this:
for(var i in CKEDITOR.instances) {
alert(CKEDITOR.instances[i].name);
}
The alert is just blank-- so there's no name associated with it apparently.
I should also mention, that despite my best efforts, I cannot seem to get the editable text to have a menu appear above it like it does in the Massive Inline Editing Example
Thanks for any assistance you can bring.
Jason Silver
UPDATE:
I'm showing off my lack of knowledge here, but I had never come across "contenteditable='true'" before, so thought that because I was able to type inline, therefore the editor was instantiated somehow... but now I'm wondering if the editor is even being applied to my div.
UPDATE 2:
When the page is loaded and the script is initially called, the div does not exist. The editable div is sent into the DOM using AJAX. #Zee left a comment below that made me wonder if there is some other command that should be called in order to apply the editor to that div, so I created a button in the page with the following onclick as a way to test this approach: (adapted from the ajax example)
var editor,html='';config = {};editor=CKEDITOR.appendTo('editable',config, html );
That gives the following error in Chrome:
> Uncaught TypeError: Cannot call method 'equals' of undefined
> + CKEDITOR.tools.extend.getEditor ckeditor.js:101
> b ckeditor.js:252
> CKEDITOR.appendTo ckeditor.js:257
> onclick www.pediatricjunction.com:410
Am I headed in the right direction? Is there another way to programmatically tell CKEditor to apply the editor to a div?
UPDATE 3:
Thanks to #Reinmar I had something new to try. The most obvious way for me to test to see if this was the solution was to put a button above the content editable div that called CKEDITOR.inlineAll() and inline('editable') respectively:
<input type='button' onclick=\"CKEDITOR.inlineAll();\" value='InlineAll'/>
<input type='button' onclick=\"CKEDITOR.inline('editable');\" value='Inline'/>
<input type='button' onclick=\"var editor = CKEDITOR.inline( document.getElementById( 'editable' ) );\" value='getElementById'/>
This returned the same type of error in Chrome for all three buttons, namely:
Uncaught TypeError: Cannot call method 'equals' of undefined ckeditor.js:101
+ CKEDITOR.tools.extend.getEditor ckeditor.js:101
CKEDITOR.inline ckeditor.js:249
CKEDITOR.inlineAll ckeditor.js:250
onclick
UPDATE 4:
Upon further fiddling, I've tracked down the problem being related to json2007.js, which is a script I use which works with Real Simple History (RSH.js). These scripts have the purpose of tracking ajax history, so as I move forward and back through the browser, the AJAX page views is not lost.
Here's the fiddle page: http://jsfiddle.net/jasonsilver/3CqPv/2/
When you want to initialize inline editor there are two ways:
If element which is editable (has contenteditable attribute) exists when page is loaded CKEditor will automatically initialize an instance for it. Its name will be taken from that element's id or it will be editor<number>. You can find editors initialized automatically on this sample.
If this element is created dynamically, then you need to initialize editor on your own.
E.g. after appending <div id="editor" contenteditable="true">X</div> to the document you should call:
CKEDITOR.inline( 'editor' )
or
CKEDITOR.inlineAll()
See docs and docs.
You can find editor initialized this way on this sample.
The appendTo method has different use. You can initialize themed (not inline) editor inside specified element. This method also accepts data of editor (as 3rd arg), when all other methods (CKEDITOR.inline, CKEDITOR.replace, CKEDITOR.inlineAll) take data from the element they are replacing/using.
Update
I checked that libraries you use together with CKEditor are poorly written and cause errors you mentioned. Remove json2007.js and rsh.js and CKEditor works fine.
OK, so I have tracked down the problem.
The library I was using for tracking Ajax history and remembering commands for the back button, called Real Simple History, was using a script called json2007 which was intrusive and extended native prototypes to the point where things broke.
RSH.js is kind of old, and I wasn't using it to it's full potential anyway, so my final solution was to rewrite the essential code I needed for that, namely, a listener that watched for anchor (hash) changes in the URL, then parsed those changes and resubmitted the ajax command.
var current_hash = window.location.hash;
function check_hash() {
if ( window.location.hash != current_hash ) {
current_hash = window.location.hash;
refreshAjax();
}
}
hashCheck = setInterval( "check_hash()", 50 );
'refreshAjax()' was an existing function anyway, so this is actually a more elegant solution than I was using with Real Simple History.
After stripping out the json2007.js script, everything else just worked, and CKEditor is beautiful.
Thanks so much for your help, #Reinmar... I appreciate your patience and effort.

How can I make a "reverse preventDefault" in jQuery?

In Private Logistics: Privacy-Sensitive Calendar, Todo, and Personal Information Management, data that is entered can be edited with a click, and there is support for either entering a link as <a href="... or entering a URL, which will be linkified.
This works great but it presents a problem when someone clicks on a link. The desired behavior is for the link to open and not to put the snippet of text into edit mode, which is the reverse of the usual pattern implemented by event.preventDefault()' or '...return false;}. (Clicks outside the link on the element should put the containing element in edit mode, same as a container that doesn't happen to have a link.)
How can I reverse the more common pattern using jQuery? My best guess now is to attempt introspection on the event target and see if it is an anchor. But that's just a best guess; I have seen plenty of examples of the pattern that would cancel the link loading another page but performing the added Ajax functionality of putting the container into edit mode; I'm not sure I've seen the reverse of that pattern which would follow the link and not put the container into edit mode.
I also see a way to dodge the matter by having links load in the same page, but that's the sort of solution I'd prefer to only adopt if there are intractable issues with implementation or the like.
Generally, you don't want to clean up your broad strokes, instead, don't make such broad strokes. Use an if statement prior to running e.preventDefault().
Something like:
var preventedLinks = $('a.preventthislink');
$('a').click(function(e){
if ($(this).index(preventedLinks) != -1) {
e.preventDefault();
}
});
you could alternatively just change the class of whatever you are preventing default on:
$(document).ready(function(){
$('.blue').removeClass('blue').addClass('green');
});

Prefixing a URL in an window.open function jQuery

I have this HTML:
Track Your Package »
Somebody on this site was able to provide me with a script to prefix the URL with the domain http://www.example.com/ Here's the script:
$(document).ready(function(){
$('a[onclick^="window.open(\'TrackPackage.asp"]').attr('onClick', $('a[onclick^="window.open(\'TrackPackage.asp"]').attr('onClick').replace("window.open('", "window.open('http://www.example.com/"));
});
However, I am having a little trouble with this:
The first issue is where there is multiple instances of the element. Here's a fiddle: http://jsfiddle.net/VMmZx/
Instead of one anchor being signed with ID=4 and the other with ID=5 as intended, they're both being signed with ID=4.
The idea is, each window.open function should be prefixed with http://www.example.com however, the remainder of the URL should remain intact...
The second problem I'm encountering is when the element does not exist on a page, the remainder of the jQuery fails...
Here's another fiddle: http://jsfiddle.net/VPf32/
The <a> should get the class foo, but since the element does not exist on the page, the jQuery does not execute.
Since the JavaScript is being included in the HTML template of the ASP.NET server, this can create many problems.
I hope I've been clear and you can help me. Thanks.
You can use .each() to iterate over each matching element and change them individually:
$('a[onclick^="window.open(\'TrackPackage.asp"]').each(function(index, element) {
element = $(element);
element.attr('onclick', element.attr('onclick').replace(/open\('/, 'open(\'http://www.example.com/'));
});​
However, I don't think using links with a href of # and an onclick opening a window is as semantic as it could be. If possible, try changing the markup to this:
Track Your Package »
Now if someone is curious where it will lead them, the browser can show something useful in the status bar when you hover over it.
If you need to adjust the behavior further, add a class and bind for the click event. When they click, prevent the default action and open the window yourself, as you did before.
Why are you doing the click even inline like that? I would just output the links like:
Link Text
And then:
$('a[target=_blank]').click(function(){
var prefix = 'http://domain.com';
window.open(prefix + $(this).attr('href'));
});

Is there a way to link to the middle of someone else's page even if they don't have an anchor?

...something along the lines of telling the browser which percent of the page to center to?
Yes you can. If the person has an element with an ID anywhere on the page. For example:
<div id="someId"></div>
Then you can create a link to this page like:
Middle!
The only thing you need to do is choose an Id in the middle.
No, you can't do this without anchors. You would need to access the DOM in order to do a scrollTo or something like that, which is prohibited on different domains. Security being the main reason.
{using Google Chrome web browser; remeber wiki is dynamic and the following URL may get invalid at anytime, the process is still valid though!}
1_ This is the main URL:
https://en.wikipedia.org/wiki/RSA_(cryptosystem)
2_ I want to refer to "A worked example" in the middle of the page
3_ right click on "A worked example" -> Inspect Element -> Edit as HTML
4_ you should see this:
<span class="mw-headline" id="A_worked_example">A worked example</span>
5_ The id is id="A_worked_example". Copy-paste it in the following sentence as follows:
Middle! :
Middle!
6_ There you go:
https://en.wikipedia.org/wiki/RSA_(cryptosystem)#A_worked_example
:)

Categories

Resources