Using Keen.io with CoffeeScript doesn't work? - javascript

I'm trying to use Keen.io, I converted their JS to coffee as follows:
# Keen init
Keen = Keen or
configure: (e) ->
#_cf = e
addEvent: (e, t, n, i) ->
#_eq = #_eq or []
#_eq.push([e, t, n, i])
setGlobalProperties: (e) ->
#_gp = e
onChartsReady: (e) ->
#_ocrq = #_ocrq or []
#_ocrq.push(e)
(->
e = document.createElement("script")
e.type = "text/javascript"
e.async = not 0
e.src = ((if "https:" is document.location.protocol then "https://" else "http://")) + "dc8na2hxrj29i.cloudfront.net/code/keen-2.1.0-min.js"
t = document.getElementsByTagName("script")[0]
t.parentNode.insertBefore e, t
)()
Keen.configure myParams
Keen.addEvent "script_tag_init"
But looks like events aren't hitting. What gives?

Yeah, that would be the problem. The Keen object won't be visible to the global scope due to how the CoffeeScript will compile.
"Exporting" Keen to window after initializing will work.
Alternatively you can initialize Keen directly on the window object:
# Keen init
window.Keen =
configure: (e) ->
#_cf = e
...
Note: This method does exclude checking if Keen already exists on the page first, which is a corner-case performance optimization and isn't necessary for most applications. In other words it should be fine.

Since coffee wraps everything in a closure, you need to include this after the call to configure:
# Keen works with variable as it is attached to window
window.Keen = Keen

Related

Can I protect custom events from "preventDefault"?

We have a Stencil web component that renders a user dialog. It consists of an "outerComponent" and an "innerComponent".
The outer one cares about dealing with the browser (props, load stuff from cookies etc.) and the inner one renders the actual HTML and lets the user operate it.
(Actually there are more components used inside, from a different project for the UI components such as checkbox, button etc. But I don't think that's relevant here.)
When a checkbox, button etc. is clicked in <inner-component> an onclick-handler within the component is called that executes some UI logic (e.g. set the "checked" property) and then emits a custom event, e.g.:
#Event() checkboxToggleModalEvent: EventEmitter<OptionType>;
...
<checkbox-comp fid="...">
<input type="checkbox" checked={optionCheckbox.userSelection} onClick={this.handleCheckbox} />
...
</checkbox-comp>
...
private handleCheckbox(event: Event) {
const checkboxElement: HTMLInputElement = event.target as HTMLInputElement;
...
const selection: OptionType = { name: indexId, userSelection };
this.checkboxToggleModalEvent.emit(selection);
}
Now, in <outer-component> this event is listened for and the handler cares for the "technical" logic:
#Listen("checkboxToggleModalEvent")
checkboxToggleModalEventHandler(event) {
LogService.log.debug(event);
... some technical logic
}
This works fine in most cases. Now we have an integration on one site, where the events apparently do not get emitted correctly or somehow lost in the middle.
The UI logic is executed normally but the handler in outerComponent never gets called.
I was able to find the piece of code from an integrated library that causes the problem (sorry for pasting the whole function!):
// From the imported library on customer website:
function(t, exports) {
try {
var e = new window.CustomEvent("test");
if (e.preventDefault(),
!0 !== e.defaultPrevented)
throw new Error("Could not prevent default")
} catch (t) {
var n = function(t, e) {
var n, r;
return e = e || {
bubbles: !1,
cancelable: !1,
detail: void 0
},
n = document.createEvent("CustomEvent"),
n.initCustomEvent(t, e.bubbles, e.cancelable, e.detail),
r = n.preventDefault,
n.preventDefault = function() {
r.call(this);
try {
Object.defineProperty(this, "defaultPrevented", {
get: function() {
return !0
}
})
} catch (t) {
this.defaultPrevented = !0
}
}
,
n
};
n.prototype = window.Event.prototype,
window.CustomEvent = n
}
}
If I remove this, everything works as expected.
Now, I'm wondering if we can somehow "protect" our events from being intercepted like this as the component should really work in any case (that's why we chose this technology).
But I also would be very grateful for any hints to what might actually cause the problem.
Thanks a lot!!
n.prototype = window.Event.prototype,
window.CustomEvent = n
Looks like they overloaded CustomEvent and injected their own code.
This is the drawback of using 3rd party software.
In this case, only way to get around this is to get in early, and overload CustomEvent yourself.
But you then have the challenge of making their code work; because they did this overloading for a reason.
What is the 3rd party software? Publically shame them.
For those who want to try overloading, execute this early:
window.customeElements.define = () => {}

Why do JS SDKs exposed in window control an arguments array?

I'm building a JS SDK to be exposed in window, and I went to look into how other SDKs do it.
Intercom does this:
var i = function() {
i.c(arguments);
};
i.q = [];
i.c = function(args) {
i.q.push(args);
};
Hotjar does this:
h.hj =
h.hj ||
function() {
(h.hj.q = h.hj.q || []).push(arguments);
};
Pendo does this:
o._q = o._q || [];
v = ['initialize', 'identify', 'updateOptions', 'pageLoad', 'track'];
for (w = 0, x = v.length; w < x; ++w)
(function(m) {
o[m] =
o[m] ||
function() {
o._q[m === v[0] ? 'unshift' : 'push'](
[m].concat([].slice.call(arguments, 0))
);
};
})(v[w]);
But I don't really understand what is the purpose of this code, and from what little I gathered, it seems related to which methods they expose in their global property.. Is this something I should worry when building a web SDK and should it be in my copy-paste snippet?
Well, I figured it out myself reading the minified code.
This stuff exists in order to make the methods fully available from the moment the JavaScript is interpreted by the browser, and since it would take some time for the actual JS asset to load via network, you could potentially miss your very first method calls.
Seems like its a queue intended to be used only when the SDK first loads, processing method calls that happened while it was loading.

Add a script before </body> only on a single component - vuejs

I'm vuejs newbie, and I'm start to use the clearsale api for validations and want make a fingerprint catch for an validation, and need's call a script funcion on page's bottom only in one vuejs component. This is the script in question:
<script>
(function(a, b, c, d, e, f, g) {
a["CsdpObject"] = e;
(a[e] =
a[e] ||
function() {
(a[e].q = a[e].q || []).push(arguments);
}),
(a[e].l = 1 * new Date());
(f = b.createElement(c)), (g = b.getElementsByTagName(c)[0]);
f.async = 1;
f.src = d;
g.parentNode.insertBefore(f, g);
})(window, document, "script", "//device.clearsale.com.br/p/fp.js", "csdp");
csdp("app", "appKey");
csdp("sessionid", "sessionID");
</script>
I called out of export default scope, but thei not recognize the csdp functions.
(p.s. sorry about my english)
You should put this inline script in your public/index.html file - but without the last 2 statements (where you call the csdp function). In your component then you will write
window.csdp("app", "appKey");
window.csdp("sessionid", "sessionID");

Can I modify a Javascript library at runtime?

I use a web based development environment for data entry forms. The environment lets me create rules that are triggered by form events. These events run in js in the browser but there is almost no support for debugging, which makes problem solving a nightmare.
The code in the browser has a central event handler, which has a logging feature but the quantity of information produced by it is so large, it makes finding what you need difficult. Think of info level logging gone mad. Plus you have to open a separate window to access the log.
I need to be able to log certain events to the console, or trigger breakpoints at specified rules. Is there a way to modify the environment's code below to allow it to call my debugger instead of (or in addition) to SFLog?
function handleEvent(n,t,q,r,u,f,e,o,s,h,c,l){
if(eventsCancelled!==!0){
SFLog({type:3,source:"handleEvent",category:"Events",
message:"{2} event fired from {1} - {0}",parameters:[n,t,q]});
var b="Events/Event[#SourceID='"+n+"'][#SourceType='"+t+"'][Name/text()="+q.xpathValueEncode()+"]";
//Rest of the event handler...
function SFLog(n){
if(checkExists(_debug)){var s=translateDebugLevel(n.type);
if(s>=_debug){
varu=n.type,e=n.source,r=n.category,q=n.message,h=n.parameters,o=checkExists(n.exception)? WriteExceptionXml(n.exception):null,t=n.data,l=checkExists(n.humanateData)?
n.humanateData:!0,f=(new Date).format("yyyy-MM-ddTHH:mm:ss:fff");
checkExists(t)&&(dataString=t.xml,checkExists(dataString)||(dataString=t),l===!0&&(dataString=Humanate(dataString)));
//more code for SFLog...
Cleaned Up Code
function handleEvent(n, t, q, r, u, f, e, o, s, h, c, l) {
if (eventsCancelled !== !0) {
SFLog({
type: 3,
source: "handleEvent",
category: "Events",
message: "{2} event fired from {1} - {0}",
parameters: [n, t, q]
});
var b = "Events/Event[#SourceID='" + n + "'][#SourceType='" + t + "'][Name/text()=" + q.xpathValueEncode() + "]";
//Rest of the event handler...
}
}
function SFLog(n) {
if (checkExists(_debug)) {
var s = translateDebugLevel(n.type);
if (s >= _debug)
{
varu = n.type;
e = n.source;
r = n.category;
q = n.message;
h = n.parameters;
o = checkExists(n.exception) ?
WriteExceptionXml(n.exception) :
null;
t = n.data;
l = checkExists(n.humanateData) ?
n.humanateData :
!0;
f = (new Date).format("yyyy-MM-ddTHH:mm:ss:fff");
checkExists(t) &&
(dataString = t.xml, checkExists(dataString) ||
(dataString = t), l === !0 && (dataString = Humanate(dataString)));
//more code for SFLog.
I agree with #Eddie but one solution could be to wrap the logger function and and override it, and only log the events you care about. e.g.:
function SFLog(n){
//old code
}
//run on the console, the first line, and then the second.
var oldLoggger = SFLog;
function SFLog(n) {
if(/*some criteria*/) {
oldLogger(n);
}
}
This way you can run the default logger with different conditions, but it probably would be best if you could modify the logger code itself to accept certain criteria, like, event type to log, or targetElement's ID, class etc.
PD: If you need to modify the eventHandler itself, you should:
remove the event handler first.
create your wrapper function.
add the wrapper function as event handler

Delayed trigger for Backbone on Nodejs

B = require 'backbone'
U = require 'underscore'
o = {}
U.extend o, B.Events
o.on 'e', console.log
setTimeout o.trigger, 5000, 'e', 'Hi!'
Why did Nodejs console not log for the delayed Backbone #trigger above?
#Edit
Q = require 'q'
d = Q.defer()
d.promise.then console.log
setTimeout d.resolve, 5000, 'Hi!'
This worked flawlessly. But why did the console not log if Q #resolve was wrapped in the anonymous function below,
setTimeout (-> d.resolve 'Hi!'), 5000
#Edit 2
Actually the wrapped version Q #resolve also worked if being invoked at first and once.
Why the plain version Q #resolve worked while Backbone #trigger didn't, is the only remaining question.
#Edit 3
R = require 'rx'
src = new R.BehaviorSubject 0
dst = src.map (v) -> v + 1
dst.subscribe console.log
setTimeout src.onNext, 5000, 1
Rx #onNext had similar problem and solution to Backbone #trigger.
All above can be sourced to the varying this context, e.g. a bare version shows the problem below,
o =
f: ->
g: -> #f()
setTimeout o.g
then,
TypeError: Object [object Object] has no method 'f'
The wrapped version below thus goes through.
setTimeout -> o.g()
Below shows this context switch to cause the problem and the wrapper to solve it,
f = (g) -> g.apply #
o =
x: 'Hi!'
g: -> console.log #x
f o.g # undefined
f -> o.g() # 'Hi!'
#Edit 4
Additionally, Coffeescript => binding to this varies to -> below,
x = 'Hi!'
o = f: => #x
console.log o.f() # Hi!
console.log -> o.f() # undefined
Because when you pass o.trigger as an argument to setTimeout you execute trigger function not as an method for o object but instead you execute it in global scope. That is in this case this inside trigger will point not to o but to global object.
So before passing o.trigger as an argument to setTimeout you need to wrap it in anonymous function.
Unfortunately I'm not good in Coffee Script but I can show you how your code should look like in pure JavaScript:
var B, U, o;
B = require('backbone');
U = require('underscore');
o = {};
U.extend(o, B.Events);
o.on('e', console.log);
setTimeout(function () {
o.trigger('e', 'Hi!');
}, 5000);
Hope this will help. Good luck.

Categories

Resources