How to set highlight duration permanently - javascript

I want to set the duration time of the Ext.get(el).highlight() function permanently. Is this possible without using cls? I have already tried to give infinity to the duration config. However I receive many errors by doing that.

You need to override function highlight. There is constant 1000ms.
Ext.dom.Element.override({
highlight: function(color, options) {
var me = this,
dom = me.dom,
from = {},
animFly = new Ext.dom.Fly(),
restore, to, attr, lns, event, fn;
options = options || {};
lns = options.listeners || {};
attr = options.attr || 'backgroundColor';
from[attr] = color || 'ffff9c';
if (!options.to) {
to = {};
to[attr] = options.endColor || me.getColor(attr, 'ffffff', '');
}
else {
to = options.to;
}
// Don't apply directly on lns, since we reference it in our own callbacks below
options.listeners = Ext.apply(Ext.apply({}, lns), {
beforeanimate: function() {
// Reattach to the DOM in case the caller animated a Fly
// in which case the dom reference will have changed by now.
animFly.attach(dom);
restore = dom.style[attr];
animFly.clearOpacity();
animFly.show();
event = lns.beforeanimate;
if (event) {
fn = event.fn || event;
return fn.apply(event.scope || lns.scope || WIN, arguments);
}
},
afteranimate: function() {
if (dom) {
dom.style[attr] = restore;
}
event = lns.afteranimate;
if (event) {
fn = event.fn || event;
fn.apply(event.scope || lns.scope || WIN, arguments);
}
}
});
me.animate(Ext.apply({}, options, {
duration: 10000, // here new duration ms
easing: 'ease-in',
from: from,
to: to
}));
return me;
}
});
Or you can attach config to highlight method like :
Ext.get(el).highlight("#ffff9c", {
attr: "backgroundColor",
endColor: "#ffffff",
easing: 'easeIn',
duration: 4000
});

Related

Webpack - export window.function failing

I am a total newbie in Webpack which I have started to use 3 days ago to change how we load our javascript.
The code before webpack, which is working, is used to implement a "famous" fading effect (source gist.github.com/paulirish/1579671)
window.requestNextAnimationFrame =
(function () {
var originalWebkitRequestAnimationFrame = undefined,
wrapper = undefined,
callback = undefined,
geckoVersion = 0,
userAgent = navigator.userAgent,
index = 0,
self = this;
// Workaround for Chrome 10 bug where Chrome
// does not pass the time to the animation function
if (window.webkitRequestAnimationFrame) {
// Define the wrapper
wrapper = function (time) {
if (time === undefined) {
time = +new Date();
}
self.callback(time);
};
// Make the switch
originalWebkitRequestAnimationFrame = window.webkitRequestAnimationFrame;
window.webkitRequestAnimationFrame = function (callback, element) {
self.callback = callback;
// Browser calls the wrapper and wrapper calls the callback
originalWebkitRequestAnimationFrame(wrapper, element);
}
}
// Workaround for Gecko 2.0, which has a bug in
// mozRequestAnimationFrame() that restricts animations
// to 30-40 fps.
if (window.mozRequestAnimationFrame) {
// Check the Gecko version. Gecko is used by browsers
// other than Firefox. Gecko 2.0 corresponds to
// Firefox 4.0.
index = userAgent.indexOf('rv:');
if (userAgent.indexOf('Gecko') != -1) {
geckoVersion = userAgent.substr(index + 3, 3);
if (geckoVersion === '2.0') {
// Forces the return statement to fall through
// to the setTimeout() function.
window.mozRequestAnimationFrame = undefined;
}
}
}
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function (callback, element) {
var start,
finish;
window.setTimeout( function () {
start = +new Date();
callback(start);
finish = +new Date();
self.timeout = 1000 / 60 - (finish - start);
}, self.timeout);
};
}
)
();
// It's then used here in our code here:
loadIcons();
function loadCompanyIcons() {
var elements = document.querySelectorAll('img');
if (!elements) return;
Array.prototype.forEach.call(elements, function(el, i){
var watcher = scrollMonitor.create(el, 2000);
watcher.enterViewport(function() {
var srcToInject = el.getAttribute('data-src');
var src = el.getAttribute('src');
if (src === null && srcToInject!=null) { // do not re-execute for images already with injected src
el.style.opacity = 0;
el.style.display = "block";
el.setAttribute('src',srcToInject);
el.onload = imageFound;
el.onerror = imageNotFound;
function imageFound() {
// progressively show image via opacity variation
(function fade() {
var val = parseFloat(el.style.opacity);
if (!((val += .1) > 1)) {
el.style.opacity = val;
requestNextAnimationFrame(fade);
}
})();
}
}
});
});
}
It perfectly works when used on a basic js file.
When we tried to move to Webpack and use "exports" we hit a wall. Most Webapck export we do have been working so I think this one does not work because it's not a standard:
function doSth() {
}
But it starts with window.doSth()...
Here's what we do today which is failing:
js/helpers/requestAnimationFramePolyfill.js
export window.requestNextAnimationFrame =
(function () {
var originalWebkitRequestAnimationFrame = undefined,
wrapper = undefined,
callback = undefined,
geckoVersion = 0,
userAgent = navigator.userAgent,
index = 0,
self = this;
// Workaround for Chrome 10 bug where Chrome
// does not pass the time to the animation function
if (window.webkitRequestAnimationFrame) {
// Define the wrapper
wrapper = function (time) {
if (time === undefined) {
time = +new Date();
}
self.callback(time);
};
// Make the switch
originalWebkitRequestAnimationFrame = window.webkitRequestAnimationFrame;
window.webkitRequestAnimationFrame = function (callback, element) {
self.callback = callback;
// Browser calls the wrapper and wrapper calls the callback
originalWebkitRequestAnimationFrame(wrapper, element);
}
}
// Workaround for Gecko 2.0, which has a bug in
// mozRequestAnimationFrame() that restricts animations
// to 30-40 fps.
if (window.mozRequestAnimationFrame) {
// Check the Gecko version. Gecko is used by browsers
// other than Firefox. Gecko 2.0 corresponds to
// Firefox 4.0.
index = userAgent.indexOf('rv:');
if (userAgent.indexOf('Gecko') != -1) {
geckoVersion = userAgent.substr(index + 3, 3);
if (geckoVersion === '2.0') {
// Forces the return statement to fall through
// to the setTimeout() function.
window.mozRequestAnimationFrame = undefined;
}
}
}
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function (callback, element) {
var start,
finish;
window.setTimeout( function () {
start = +new Date();
callback(start);
finish = +new Date();
self.timeout = 1000 / 60 - (finish - start);
}, self.timeout);
};
}
)
();
// It's then used here in our code here:
loadIcons();
function loadIcons() {
var elements = document.querySelectorAll('img');
if (!elements) return;
Array.prototype.forEach.call(elements, function(el, i){
var watcher = scrollMonitor.create(el, 2000);
watcher.enterViewport(function() {
var srcToInject = el.getAttribute('data-src');
var src = el.getAttribute('src');
if (src === null && srcToInject!=null) { // do not re-execute for images already with injected src
el.style.opacity = 0;
el.style.display = "block";
el.setAttribute('src',srcToInject);
el.onload = imageFound;
el.onerror = imageNotFound;
function imageFound() {
// progressively show image via opacity variation
(function fade() {
var val = parseFloat(el.style.opacity);
if (!((val += .1) > 1)) {
el.style.opacity = val;
requestNextAnimationFrame(fade);
}
})();
}
}
});
});
}
then we do in main.js
import {requestNextAnimationFrame} from './helpers/requestAnimationFramePolyfill.js'
loadIcons();
function loadCompanyIcons() {
var elements = document.querySelectorAll('img');
if (!elements) return;
Array.prototype.forEach.call(elements, function(el, i){
var watcher = scrollMonitor.create(el, 2000);
watcher.enterViewport(function() {
var srcToInject = el.getAttribute('data-src');
var src = el.getAttribute('src');
if (src === null && srcToInject!=null) { // do not re-execute for images already with injected src
el.style.opacity = 0;
el.style.display = "block";
el.setAttribute('src',srcToInject);
el.onload = imageFound;
el.onerror = imageNotFound;
function imageFound() {
// progressively show image via opacity variation
(function fade() {
var val = parseFloat(el.style.opacity);
if (!((val += .1) > 1)) {
el.style.opacity = val;
requestNextAnimationFrame(fade);
}
})();
}
}
});
});
}
We also tried:
import {window.requestNextAnimationFrame} from './helpers/requestAnimationFramePolyfill.js'
but none work and we know this because the icons supposed to use requestAnimationFramePolyfill.js to progressively fade iunto a 1.0 opacity, remain with 0.1 opacity.
I'm not sure though this is the reason. I could not understand it for the past day.
You are trying to add a function in to window object then use it in other place. It's one way to make a function access able by other files, but with ES6 and webpack you can do it other way.
I suggest to not use variable window because its may cause some issue with window syntax. Also you do not need to add a function to window object anymore.
This should work for you.
js/helpers/requestAnimationFramePolyfill.js
const requestNextAnimationFrame = (function { your function });
export { requestNextAnimationFrame };
main.js
import { requestNextAnimationFrame } from './helpers/requestAnimationFramePolyfill.js'

Touch for Mithril with Node-webkit

I've been trying to get mithril touch to work using a good code on github:
https://gist.github.com/webcss/debc7b60451f2ad2af41
import m from 'mithril'
/*****************************************
/* DOM touch support module
/*****************************************/
if (!window.CustomEvent) {
window.CustomEvent = function (event, params) {
params = params || { bubbles: false, cancelable: false, detail: undefined };
var evt = document.createEvent('CustomEvent');
evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail);
return evt;
};
window.CustomEvent.prototype = window.Event.prototype;
}
(function(document) {
var TAPTRESHOLD = 200, // time within a double tap should have happend
TAPPRECISION = 60 / 2, // distance to identify a swipe gesture
touch = { },
tapCount = 0, // counts the number of touchstart events
tapTimer = 0, // timer to detect double tap
isTouchSwipe = false, // set to true whenever
absolute = Math.abs,
touchSupported = 'ontouchstart' in window;
function parentIfText (node) {
return 'tagName' in node ? node : node.parentNode;
}
function dispatchEvent(type, touch) {
if(touchSupported) {
touch.originalEvent.preventDefault();
touch.originalEvent.stopImmediatePropagation();
}
var event = new CustomEvent(type, {
detail: touch,
bubbles: true,
cancelable: true
});
touch.target.dispatchEvent(event);
console.log(type);
touch = { };
tapCount = 0;
return event;
}
function touchStart(e) {
if( !touchSupported || e.touches.length === 1) {
var coords = e.targetTouches ? e.targetTouches[0] : e;
touch = {
originalEvent: e,
target: parentIfText(e.target),
x1: coords.pageX,
y1: coords.pageY,
x2: coords.pageX,
y2: coords.pageY
};
isTouchSwipe = false;
tapCount++;
if (!e.button || e.button === 1) {
clearTimeout(tapTimer);
tapTimer = setTimeout(function() {
if(absolute(touch.x2 - touch.x1) < TAPPRECISION &&
absolute(touch.y2 - touch.y2) < TAPPRECISION &&
!isTouchSwipe) {
dispatchEvent((tapCount===2)? 'dbltap' : 'tap', touch);
clearTimeout(tapTimer);
}
tapCount = 0;
}, TAPTRESHOLD);
}
}
}
function touchMove(e) {
var coords = e.changedTouches ? e.changedTouches[0] : e;
isTouchSwipe = true;
touch.x2 = coords.pageX;
touch.y2 = coords.pageY;
/* the following is obsolete since at least chrome handles this
// if movement is detected within 200ms from start, preventDefault to preserve browser scroll etc.
// if (touch.target &&
// (absolute(touch.y2 - touch.y1) <= TAPPRECISION ||
// absolute(touch.x2 - touch.x1) <= TAPPRECISION)
// ) {
// e.preventDefault();
// touchCancel(e);
// }
*/
}
function touchCancel(e) {
touch = {};
tapCount = 0;
isTouchSwipe = false;
}
function touchEnd(e) {
var distX = touch.x2 - touch.x1,
distY = touch.y2 - touch.y1,
absX = absolute(distX),
absY = absolute(distY);
// use setTimeout here to register swipe over tap correctly,
// otherwise a tap would be fired immediatly after a swipe
setTimeout(function() {
isTouchSwipe = false;
},0);
// if there was swipe movement, resolve the direction of swipe
if(absX || absY) {
if(absX > absY) {
dispatchEvent((distX<0)? 'swipeleft': 'swiperight', touch);
} else {
dispatchEvent((distY<0)? 'swipeup': 'swipedown', touch);
}
}
}
document.addEventListener(touchSupported ? 'touchstart' : 'mousedown', touchStart, false);
document.addEventListener(touchSupported ? 'touchmove' : 'mousemove', touchMove, false);
document.addEventListener(touchSupported ? 'touchend' : 'mouseup', touchEnd, false);
// on touch devices, the taphold complies with contextmenu
document.addEventListener('contextmenu', function(e) {
e.preventDefault();
e.stopImmediatePropagation();
dispatchEvent('taphold', {
originalEvent: e,
target: parentIfText(e.target)
});
}, false);
if (touchSupported) {
document.addEventListener('touchcancel', touchCancel, false);
}
}(window.document));
m.touchHelper = function(options) {
return function(element, initialized, context) {
if (!initialized) {
Object.keys(options).forEach(function(touchType) {
element.addEventListener(touchType, options[touchType], false);
});
context.onunload = function() {
Object.keys(options).forEach(function(touchType) {
element.removeEventListener(touchType, options[touchType], false);
});
};
}
};
};
The only thing I've added is import m from 'mithril'.
Launching the app I can see that everything is registering as should through the console, however, in my main code I want to use that touch data:
const app = {
view: vnode => {
return m('.main', {config: m.touchHelper({ 'tap': consoleLog})
}
}
function consoleLog() {
console.log('Triggered')
}
However, this function is not triggered.
I don't know how much Mithril has changed since February 2017 (I have only recently picked up Mithril), but that m.touchHelper seems weird. What are element, initialized and context? Why is a function returned; is it ever called?
Using m.touchHelper with the config attribute seems also weird. When you do this:
return m('.main', {config: m.touchHelper({'tap': consoleLog})})
the resulting DOM element looks like this:
<div config="function(element, initialized, context) {
if (!initialized) {
Object.keys(options).forEach(function(touchType) {
element.addEventListener(touchType, options[touchType], false);
});
context.onunload = function() {
Object.keys(options).forEach(function(touchType) {
element.removeEventListener(touchType, options[touchType], false);
});
};
}
}" class="main"></div>
See JSFiddle with your code. (Note that I added missing }) to the end of app's view method.)
I would change m.touchHelper to something like this:
m.touchHelper = function(vnode, options) {
if (vnode.state.initialized) return;
vnode.state.initialized = true;
Object.keys(options).forEach(function(touchType) {
vnode.dom.addEventListener(touchType, options[touchType], false);
});
// Note that I removed the `context.unload` part as I'm unsure what its purpose was
};
And call it in a component's oncreate lifecycle method:
const app = {
oncreate(vnode) {
m.touchHelper(vnode, {'tap': consoleLog});
},
view: vnode => {
return m('.main');
}
};
Then it seems to work. See JSFiddle with updated code.

Js chess call sub function

My question is: How is it possible to call the function mova from outside the function init?
init.mova("a2-a3"); doesn't work
The full code is here.
This is a chessboard system.
I don't now how to call the function mova from outside init. init.mova doesn't work.
Code:
var init = function() {
//--- start example JS ---
var board,
game = new Chess(),
statusEl = $('#status'),
fenEl = $('#fen'),
pgnEl = $('#pgn');
// do not pick up pieces if the game is over
// only pick up pieces for the side to move
var onDragStart = function(source, piece, position, orientation) {
if (game.game_over() === true ||
(game.turn() === 'w' && piece.search(/^b/) !== -1) ||
(game.turn() === 'b' && piece.search(/^w/) !== -1)) {
return false;
}
};
var onDrop = function(source, target) {
// see if the move is legal
var move = game.move({
from: source,
to: target,
promotion: 'q' // NOTE: always promote to a queen for example simplicity
});
if (move !== null) {
console.log(move.to);
}
// illegal move
if (move === null) return 'snapback';
updateStatus();
};
// update the board position after the piece snap
// for castling, en passant, pawn promotion
var onSnapEnd = function() {
board.position(game.fen());
};
var updateStatus = function() {
var status = '';
var moveColor = 'White';
if (game.turn() === 'b') {
moveColor = 'Black';
}
// checkmate?
if (game.in_checkmate() === true) {
status = 'Game over, ' + moveColor + ' is in checkmate.';
}
// draw?
else if (game.in_draw() === true) {
status = 'Game over, drawn position';
}
// game still on
else {
status = moveColor + ' to move';
// check?
if (game.in_check() === true) {
status += ', ' + moveColor + ' is in check';
}
}
statusEl.html(status);
fenEl.html(game.fen());
pgnEl.html(game.pgn());
};
var cfg = {
draggable: true,
position: 'start',
onDragStart: onDragStart,
onDrop: onDrop,
onSnapEnd: onSnapEnd
};
board = new ChessBoard('board', cfg);
updateStatus();
//--- end example JS ---
var mova = function(positie) {
board.move(positie);
}
}; // end init()
$(document).ready(init);
init.mova("a2-a3");
Variables defined within a function are scoped to that function. They cannot be called from outside of the function.
If you wanted a quick and dirty fix, you could define the variable mova outside the init() function, and then assign its value within it.
var mova;
var init = function() {
// etc. etc.
mova = function(positie) {
board.move(positie);
}
}
then, the mova function would be available outside of the init function once it has run.
You could ensure that you don't try to use the function until it's defined by using a function that is called when your init completes:
var mova;
var init = function() {
// etc. etc.
mova = function(positie) {
board.move(positie);
}
onInitComplete();
}
function onInitComplete() {
// function using mova function
}
It's likely, given the structure of your program, that you will want to use the same technique for many variables other than just mova. You probably don't want all of your game logic inside the init() function. You could define some variables for the state of your game outside the init function and then just assign them their starting values inside it. Hope that helps.

Removing eventhandlers not working: "this" context lost in Javascript?

I have a problem with removing the eventhandlers for a slider element
If I don't use proxy for the handler, the "this" will point to the dom element
How do I remove the handler?
Relevant code:
var slider = (function (slider) {
var Sliderhandle = function(handle){
EvtTarget.call(this);
this.events = {
start: ['touchstart', 'mousedown'],
move: ['touchmove', 'mousemove'],
end: ['touchend', 'touchcancel', 'mouseup']
};
this.options = {};
this.element = $$('div.ui-slider');
// set context for event handlers
this.start = this.start.bind(this);
this.move = this.move.bind(this);
this.end = this.end.bind(this);
this.proxy = function(func){
var that = this;
return(function(){
return func.apply(that,arguments);
});
}
Object.defineProperty(this, "__el",{
value:handle
});
};
Sliderhandle.prototype = Object.create(EvtTarget.prototype,{
init : {
value:function(config){
this.container = $$('div.ui-slider');
this.track = this.container.getElementsByClassName('ui-slider-track')[0];
this.value = (config && config.value) || 1;
this.min = (config && config.min) || 1;
this.max = (config && config.value) || 1000;
this.change = (config && config.change) || null; // callback
this.addEvents("start");
this.setValue(this.value);
},
enumerable:true
},
addEvents : {
value:function(name){
var list = this.events[name],
handler = this[name],
all;
handler = this.proxy(handler);
for (all in list){
this.container.addEventListener(list[all], handler, false);
}
},
enumerable:true
},
removeEvents:{
value:function(name){
var list = this.events[name],
handler = this[name],
all;
//handler = this.proxy(handler);
for (all in list){
this.container.removeEventListener(list[all], handler, false);
}
},
enumerable:true
},
The problem is because there's no event listener same with handler which passed to removeEventListener. this.proxy() generates new function for each call. It returns whole different function object even if you call it with same parameter, although the returned function will do semantically same job.
You should store proxy functions when add, then use that one when remove like this:
var Sliderhandle = function(handle){
// ....
this.proxyHandler = {};
}
// ....
addEvents : {
value: function(name){
var list = this.events[name],
handler = this[name],
all;
this.proxyHandler[name] = handler = this.proxy(handler);
for (all in list){
this.container.addEventListener(list[all], handler, false);
}
},
enumerable:true
},
removeEvents:{
value:function(name){
var list = this.events[name],
handler = this.proxyHandler[name],
all;
for (all in list){
this.container.removeEventListener(list[all], handler, false);
}
delete this.proxyHandler[name];
},
enumerable:true
},

using Javascript within Google Analytics event tracking code to automate category naming

So I'm attempting to implement some google analytics event tracking on dynamically generated pages. I'll be using something like
<script>
$(document).ready(function(){
$("#button1").click(function(){
_gaq.push(['_trackEvent', category, action, opt_label, opt_value, opt_noninteraction)']);
});
$("#button2").click(function(){
_gaq.push(['_trackEvent', category, action, opt_label, opt_value, opt_noninteraction']);
});
});
</script>
I'm wondering is it possible to use something like document.title to auto generate the category section of the GA code from the html title of the pages? All the pages use unique titles and it would be great if the events tracked on those pages could show up in GA as separate entries and not just category.
That was tougher than I expected it. Hope it helps.
Live demo with examples
javascript
// Unbind default behaviour
$(document).off("ready.ga").on("ready", function () {
//hollow out
pageLoc = $(location).attr('href');
// Introduce helper functions.
(function ($, window, undef) {
// ga selector.
$.extend($.expr[":"], {
ga: function (a) {
var attr = a.attributes,
len = attr.length;
while (len--) {
if (attr[len].name.indexOf("data-ga-") !== -1) {
return true;
}
}
return false;
}
});
$.gaaApi = {
trackEvent: {
event: {
value: "_trackEvent",
validation: "isString",
type: "string"
},
category: {
value: null,
validation: "optString",
type: "currentloc"
},
action: {
value: null,
validation: "optString",
type: "string"
},
label: {
value: null,
validation: "optString",
type: "string"
},
value: {
value: null,
validation: "optInt",
type: "integer"
},
nonInteraction: {
value: null,
validation: "optBool",
type: "boolean"
}
},
trackPageview: {
event: {
value: ["trackPageview", $(location).attr('href')],
validation: "isString",
type: "string"
},
url: {
value: undef,
validation: "optString",
type: "string"
}
}
};
var validation = {
isString: function (obj) {
var empty = true;
if (obj && typeof obj === "string") {
empty = /^\s*$/.test(obj);
}
// If empty === true then something is wrong and we should return false.
return !(empty);
},
optString: function (obj) {
if (obj === undef) {
return true;
}
return validation.isString(obj);
},
isInt: function (obj) {
return (/^[\-+]?\d+$/).test(obj) || (obj === +obj && obj === (obj | 0));
},
optInt: function (obj) {
if (obj === undef) {
return true;
}
return validation.isInt(obj);
},
isFloat: function (obj) {
return (/^[\-+]?\d+(\.\d+)?$/).test(obj) || (obj === +obj && obj !== (obj | 0));
},
optFloat: function (obj) {
if (obj === undef) {
return true;
}
return validation.isFloat(obj);
},
isBool: function (obj) {
return (obj === true || obj === "true") || (obj === false || obj === "false");
},
optBool: function (obj) {
if (obj === undef) {
return true;
}
return validation.isBool(obj);
}
},
methods = {
validate: function (param, name, location) {
var $element = this.$element,
data = $element.data("ga-" + name.toLowerCase()),
isValid;
//pageLoc = $(location).attr('href');
if (!validation[param.validation]) {
throw new TypeError("Unknown validation type");
}
// Check the value.
isValid = validation[param.validation](data);
if (!isValid) {
throw new Error("object validation error on " + name);
}
// Assign the value.
// Some analytics methods accept numbers as strings so we check the return type.
switch (param.type) {
case "integer":
return data ? parseInt(data, 10) : null;
case "float":
return data ? parseFloat(data) : null;
case "boolean":
return data ? Boolean(data) : null;
case "currentloc":
return data;
default:
// Default to string.
return data ? data + "" : null;
}
},
createArgs: function () {
var binder = this,
event = this.event,
args = $.map(event, function (val, key, pageLoc) {
var pageLoc = $(location).attr('href');
var value;
if (key === "event") {
// We don't want to check for the event property in the DOM.
value = val.value;
} else {
// Validate and return the correct value from the DOM.
value = methods.validate.call(binder, val, key, pageLoc);
}
return value;
});
return args;
}
},
gaa = function (element, options) {
this.$element = $(element);
this.options = $.extend({}, $.fn.gaa.defaults, options);
};
gaa.prototype = {
constructor: gaa,
trackEvent: function () {
var trackedEvent = $.Event("tracked.ga");
var currentLoc = $(location).attr('href');
this.args = methods.createArgs.call(this);
if (this.options.logit) {
if (window.console && window.console.log) {
// Push the data.
console.log("pushing to Google analytics", this.args);
this.$element.trigger(trackedEvent).trigger(currentLoc);
// this.$element.trigger(currentLocation);
}
} else {
var gaq = window._gaq;
if (gaq) {
// Set the context for our deferred callback.
var binder = this;
// Push the data.
$.when(gaq.push(args)).done(
function () {
this.$element.trigger(trackedEvent);
// this.$element.trigger(trackedEvent);
// Redirect the location - delayed so that any other page functionality has time to run.
setTimeout(function () {
var href = binder.attr("href");
if (href && href.indexOf("#") !== 0) {
window.location = href;
}
}, 100);
});
} else {
throw new ReferenceError(" _gaq not there");
}
}
}
};
// wrapper definition
$.fn.gaa = function (options) {
return this.each(function () {
var $this = $(this),
data = $this.data("ga"),
opts = typeof options === "object" ? options : null;
if (!data) {
// Check the data and assign if not present.
$this.data("ga", (data = new gaa(this, opts)));
}
// Run the appropriate function is a string is passed.
if (typeof options === "string") {
data[options]();
} else {
var handler = data.options.handler.toLowerCase(),
// Check for the event attr here as it might be other than the default.
event = data.$element.attr("data-ga-event");
// Overwrite if necessary.
$.extend(data.options, {
event: event
});
// Build the data as we have nothing there.
// First assign the event.
data.event = $.gaaApi[data.options.event];
// Then bind the handler.
if (handler === "load") {
data.trackEvent();
} else {
data.$element.on(handler + ".ga", function (e) {
e.preventDefault();
data.trackEvent();
});
}
}
});
};
// Define the defaults.
$.fn.gaa.defaults = {
event: ["trackEvent", "giveLocation"],
handler: "load",
logit: false
};
// Set the public constructor.
$.fn.gaa.Constructor = gaa;
// Let's BEGIN
$(document).on("ready.ga", function () {
// Bind using the custom selector.
$(":ga").each(function () {
$(this).gaa();
});
});
}(jQuery, window));
// Set some options the ones below are the defaults.
var options = {
event: "trackEvent", // The event name unprefixed.
handler: "click", // The eventhandler to trigger the tracking.
// Using 'load' will track immediately.
logit: true, //to logit
};
var options2 = {
event: "trackPageview", // The event name unprefixed.
handler: "click", // The eventhandler to trigger the tracking.
// Using 'load' will track immediately.
logit: true, //to logit
};
var options3 = {
event: "trackPageview", // The event name unprefixed.
handler: "load", // The eventhandler to trigger the tracking.
// Using 'load' will track immediately.
logit: true //to logit
};
// Binds using the custom selector.
$("load.trigger").gaa(options3); //fires a ga onload after domready
$("button.button1").gaa(options2).click(function () {
console.log('\nmore button events\n', 'heres the URL:', location.href)
});
$("#clickme").gaa(options).click(function () {
$(this).toggleClass("changeIt");
});
});
index.html
<load class="trigger">loading triggers ga event</load>
<button class="button1">fire ga event with address</button>
<button class="button1" id="clickme">multiple events</button>
The location bind happens here and lets jquery consume location properly.
event: {
value: ["trackPageview",$(location).attr('href')],
validation: "isString",
type: "string"
}
your approach of using this was correct but you had to get the location earlier to get it into ga. It seems like anyways this format
$("#button").gaa(options).click(function () {
$(this).toggleClass("changeIt");
});
Will get you going in the right directions.
This was a fun brainache. That should give you access to location.href where you want need it later on. The idea is to form a bind after DOM ready but before _gaq execution.

Categories