Menu
  • HOME
  • TAGS

JavaScript: CustomEvent.detail not delivered to all listeners?

Tag: javascript,google-chrome-extension,dispatch,detail,custom-event

I'm currently developing a Google Chrome extension to add some convenience to a website I'm required to use.

I need to interact with the on-page JS, and in order to do so, I append a script tag to the document head, containing a custom event listener from where I can access whatever I need.

Since I have to pack the listener code inside strings, embedding things like

{
    html: '<div onclick="doSomething(this, \'someName\')"></div>'
}

is a real pain.

Now, since there's a cool thing called CustomEvent, I thought I could use that instead to fire data forth and back between the page and my extension.
But it seems that as soon as CustomEvent.detail contains a reference to something non-JSON-serializable, the entire detail field is set to null as soon as the Event crosses the boundary between my extension and the page.

Example

Script (extension.js):

(function()
{
    var script = document.createElement('script');
    script.innerHTML = [
"window.addEventListener('xyz', function(ev)",
"    {                                      ",
"        console.log('after dispatch:');    ",
"        console.log(ev.detail);            ",
"    });                                    ",
    ].join('\n');
    document.head.appendChild(script);
    // JSON-serializable data
    var e = new CustomEvent('xyz', { detail: { x: 42, name: 'Schroedinger' } });
    console.log('before dispatch:')
    console.log(e.detail);
    window.dispatchEvent(e);
    // non-JSON-serializable data
    e = new CustomEvent('xyz', { detail: { x: 42, name: 'Schroedinger', func: function(){} } });
    console.log('before dispatch:');
    console.log(e.detail);
    window.dispatchEvent(e);
})();

Output:

before dispatch:
Object {x: 42, name: "Schroedinger"}
after dispatch:
Object {x: 42, name: "Schroedinger"}
before dispatch:
Object {x: 42, name: "Schroedinger", func: function (){}}
after dispatch:
null

This looks like a silently failing serialization to me, but I was unable to find any documentation about CustomEvent.detail being serialized at any point.
It could also be a security measure, but again, I was unable to find any documentation mentioning it, especially not the Chrome permissions list.

Tested in Chrome 40.0.2214.115m and 43.0.2357.124m.

Best How To :

What I found out

Alright, so after a lot of trial and error, I can only assume that this is indeed a security feature.
In ran an equivalent test in Firefox by putting the event listener in a separate file that could be loaded via mozIJSSubScriptLoader:

test.js:

(function()
{
    window.addEventListener('xyz', function(ev)
    {
        console.log('after dispatch:');
        console.log(ev.detail);
    });
})();

firefox.js:

(function()
{
    var mozIJSSubScriptLoader = Components.classes["@mozilla.org/moz/jssubscript-loader;1"].getService(Components.interfaces.mozIJSSubScriptLoader);
    window.addEventListener('load', function load(event)
    {
        window.removeEventListener('load', load);
        window.gBrowser.addEventListener('DOMContentLoaded', function(event)
        {
            mozIJSSubScriptLoader.loadSubScript('chrome://my-extension/content/test.js', window.content, 'UTF-8');
            // JSON-serializable data
            var e = new CustomEvent('xyz', { detail: { x: 42, name: 'Schroedinger' } });
            console.log('before dispatch:')
            console.log(e.detail);
            window.content.dispatchEvent(e);
            // non-JSON-serializable data
            e = new CustomEvent('xyz', { detail: { x: 42, name: 'Schroedinger', func: function(){} } });
            console.log('before dispatch:');
            console.log(e.detail);
            window.content.dispatchEvent(e);
        });
    });
})();

Result:

console log

(Note that the error message occurs twice.)

So in Firefox it doesn't even matter what detail contains - as long as it comes from an extension, the page is not allowed to access it.
In light of that, I would be very surprised if Chrome's behaviour was not a security measure.

Workaround

I ended up using a fairly easy (although not so pretty) workaround:
In Chrome, there's no equivalent to mozIJSSubScriptLoader, but you're allowed to append <script> tags to a page from within your extension (you're not allowed to do that in FF).
Together with chrome.extension.getURL, that can be used to run a JS file packaged with the extension in the context of the page:

(function()
{
    var script = document.createElement('script');
    script.src = chrome.extension.getURL('extension.js');
    document.head.appendChild(script);
})();

Of course that requires that

"web_accessible_resources": [ "extension.js" ]

is set in manifest.json, which isn't pretty, but shouldn't be an actual problem.

The drawback of this is, of course, that from within extension.js you no longer have access to any chrome API your extension has access to, but in my case I didn't need that. It wouldn't be too difficult to set up a proxy via CustomEvent for that though, as the biggest part of the Chrome API only requires and returns data that is JSON-serializable.

Get all prices with $ from string into an array in Javascript

javascript,regex,currency

It’s quite trivial: RegEx string.match(/\$((?:\d|\,)*\.?\d+)/g) || [] That || [] is for no matches: it gives an empty array rather than null. Matches $99 $.99 $9.99 $9,999 $9,999.99 Explanation / # Start RegEx \$ # $ (dollar sign) ( # Capturing group (this is what you’re looking for) (?: #...

Can't call fetch directly in Backbone model listenTo

javascript,backbone.js,coffeescript

The handler for each type of event is passed a certain set of arguments. The Catalog of Events has this to say about a "change" event: "change" (model, options) — when a model's attributes have changed. So if you say this: this.listenTo(members, 'change', this.fetch) then fetch will be called like...

Please can someone help me understand the exec method for regular expressions?

javascript,regex

I don't understand why it would give me two hellos back? Because the first entry in the array is the overall match for the expression, which is then followed by the content of any capture groups the expression defines. Since the expression defines one capture group, you get back...

Converting “i+=n” for-loop to $.each

javascript,jquery

A jQuery only way would be to iterate over the nth-child(4n) $('.thumbnail:nth-child(4n)').each(function(){ $(this) .prevAll('.thumbnail').andSelf() .wrapAll($('<div/>',{class:"new"})) }); Demo Considering the complexity, not sure whether the prevAll() performs better than the plain for loop. Referring one of my similar answer here...

How to get my node.js mocha test running?

javascript,node.js,mocha,supertest

Create a separate file called app.js. The only purpose of this file would be to run the server. You'll also need to export your app object from server.js. So, your server.js would look like this // set up ====================================================================== var express = require('express'); var app = express(); // create our...

Javascript: Forloop Difference between i++ and (i+1)

javascript,loops,for-loop

The i++ is using post increment, so the value of the expression i++ is what the value was in the variable i before the increment. This code: if(sortedLetters[i] !== sortedLetters[i++]) return true; does the same thing as: if(sortedLetters[i] !== sortedLetters[i]) return true; i = i + 1; As x !==...

why i don't get return value javascript

javascript,jquery,html,json,html5

the first "A" in AJAX stands for "Asynchronous" that means, it is not executed right after it has been called. So you never get the value. Maybe you could first, get the os list and then output what you need, like this: function createCheckBoxPlatform(myDatas) { $.ajax({ url: "/QRCNew/GetOS", type: "post",...

Uncaught error: Invalid type for google table column

javascript,json,google-maps,google-visualization

You should change your row data.addColumn('String', 'sitecode'); to data.addColumn('string', 'sitecode'); (non capital "s" in "string"), of course this applies to all of your added columns. Javascript is case-sensitive....

Background-image style with JS not working in ie9

javascript,jquery,html,internet-explorer

Your call of setTimeout fails in any browser, but in IE9 with an exception(what stops the further script-execution). It's a matter of time. At the moment when you call var timer = setTimeout(slideshow, 8000); slideshow is undefined , and undefined is not a valid argument for setTimeout. Wrap the call...

Cant submit form

javascript,php

Your PHP is checking if $_POST['submit'] contains a value. Your form does not contain a form element with the attribute name="submit", so therefore it fails and moves straight to the else statement. If you want to check if the form was posted then you should instead check for: if (!empty($_POST))...

Wordpress log out using URL and redirect to specify page

javascript,php,wordpress

Try wp_logout() function use the funtion . if($_GET['logout'] == 1) { ob_start(); error_reporting(0); wp_logout(); $redirect = wp_logout_url(); wp_safe_redirect( $redirect ); } ...

show/hide an overflow div on anchor

javascript,jquery,html,scroll

I've just updated your jsfiddle: http://jsfiddle.net/0sq2rfcx/8/ This should work on all browsers included IE7 $('#b1').click(function () { $('#result').show(); $("#result").animate({ scrollTop:$('#a1').parent().scrollTop() + $('#a1').offset().top - $('#a1').parent().offset().top}, "slow"); }); $('#b2').click(function () { $('#result').show(); $("#result").animate({ scrollTop:$('#a2').parent().scrollTop() + $('#a2').offset().top - $('#a2').parent().offset().top}, "slow"); }); $('#b3').click(function () { $('#result').show();...

Angular $http and Fusion Tables in IE9

javascript,angularjs,internet-explorer-9,google-fusion-tables

You should use the Angular $http.jsonp() request rather than $http.get(). JSONP or “JSON with padding” is the communication technique which allows for data to be requested from a server under a different domain (also known as a Cross Origin Request). Which is what you have used in your jQuery AJAX...

How to send current page number in Ajax request

javascript,jquery,ajax,spring-mvc,datatables

DataTables already sends parameters start and length in the request that you can use to calculate page number, see Server-side processing. If you still need to have the URL structure with the page number, you can use the code below: "ajax": { "data": function(){ var info = $('#propertyTable').DataTable().page.info(); $('#propertyTable').DataTable().ajax.url( "${contextPath}/admin/getNextPageData/"+(info.page...

Javascript function to validate contents of an array

javascript,arrays

You can use a simple array based test like var validCodes = ['IT00', 'O144', '6A1L', '4243', 'O3D5', '44SG', 'CE64', '54FS', '4422']; function validItems(items) { for (var i = 0; i < items.length; i++) { if (validCodes.indexOf(items[i]) == -1) { return items[i]; } } return ''; } var items = ["IT00",...

Replacing elements in an HTML file with JSON objects

javascript,json,replace

obj.roles[0] is a object {"name":"with whom"}. you cant replace string with object. you need to refer to property "name" in the object obj.roles[0].name Another problem is that var finalXML get a new value every line. you need to add a new value to the variable, not replcae it. var finalXML...

slideToggle state not working with multiple boxes

javascript,jquery,cookies

Use onbeforeunload function of javascript window.onbeforeunload = function() { //Declare cookie to close state } This function will be called every time page refreshes Update: To make loop through every value use this $.each this way: var new_value = ""; window.onbeforeunload = function() { $.each($('div.box_container div.box_handle'),function(index,value){ new_value = ($(value).next('.box').css('display') ==...

Login Signup PopUp

javascript

In your code you have 2 options to solve it first is jquery and second one is css. 1) Jquery On load trigger click event. $('#cont-1').click(); OR 2) CSS Add hide class in second tab <div class="tabcontent hide" id="cont-2-1"> and add activeLink class for login <a href="javascript:;" class="inactive activeLink" id="cont-1">Login</a>...

How to use a service with Http request in Angular JS

javascript,angularjs

ofcservices.getnews() is a promise You need manage with the function sucess and error ofcservices.getnews(). success(function(data) { $scope.news=data }). error(function(data, status, headers, config) { //show a error }); As weel change app.factory('news' to app.factory('newsFactory' and call it in controller('news', function($scope, newsFactory) { You can get more data about promise in the...

How To Check Value Of String

javascript,css,string,numeric

document.GetElementById("tombolco").style = "display:block"; That's not the right way. This is document.getElementById("tombolco").style.display = 'block'; Also note that it is getElementById, not with a capital G. Same with 'none',Rest of your code is fine. Fiddle...

Saving data using promises

javascript,parse.com,promise

Instead of going for recursive, you can try this: classPromise = array.map(function(obj){ return obj.save();}); in es6, same thing can be: classPromise = array.map(obj => obj.save()); Edit You can reduce the whole function to: function myFunction(array, value) { if ( !array || !array.length) return; console.log("array: " + array.length); if (!value) value...

Javascript sort array of objects in reverse chronological order

javascript,arrays,sorting

As PM 77-1 suggests, consider using the built–in Array.prototype.sort with Date objects. Presumably you want to sort them on one of start or end: jobs.sort(function(a, b) { return new Date(a.ys, a.ms-1) - new Date(b.ys, b.ms-1); }) ...

Automatically calling server side class without

javascript,html,ajax

Trigger the click event like this: $('._repLikeMore').trigger('click'); ...

JSLint error: “Expected a newline at EOF”, conflict with Beautify plugin

javascript,gruntjs,jslint,beautify

According to the Brackets Beautify Documentation, it uses JS-Beautify internally. The documentation for the latter mentions these parameters: -n, --end-with-newline -p, --preserve-newlines If you can force Adobe Brackets to pass parameters to the js-beautify call, I guess one of these should do the trick. UPDATE According to the Github repo,...

Saving image to localstorage - canvas

javascript,html5,html5-canvas

If the height or width of the canvas is 0, the string "data:," is returned. This is most likely the cause for some images to fail to receive a proper dataUrl. Check your img elements and/or scripts to obtain and set the width and height of the canvas. The...

Not able to access variables in required file

javascript,gulp,require,browserify

Without custom logic, it's not possible to achieve what you want. However I believe you could find a compromise by using ES6 modules instead of CommonJS modules. You would be able to write export var test = 'test'; which declares and exports a variable test. You can then import it...

Dynamically resize side-by-side images with different dimensions to the same height

javascript,html,css,image

If it's responsive, use percentage heights and widths: html { height: 100%; width: 100%; } body { height: 100%; width: 100%; margin: 0; padding: 0; } div.container { width: 100%; height: 100%; white-space: nowrap; } div.container img { max-height: 100%; } <div class="container"> <img src="http://i.imgur.com/g0XwGQp.jpg" /> <img src="http://i.imgur.com/sFNj4bs.jpg" /> </div>...

How to find the days b/w two long date values

javascript,jquery,date

First you need to get your timestamps in to Date() objects, which is simple using the constructor. Then you can use the below function to calculate the difference in days: var date1 = new Date(1433097000000); var date2 = new Date(1434479400000); function daydiff(first, second) { return (second - first) / (1000...

want to show and hide text using “this” jquery

javascript,jquery

I guess OP wants to link the button more with corresponding click span class $('.clickme').click(function(){ $(this).parent().prev().find(".click").toggle(); }); FIDDLE DEMO...

Error: [$injector:unpr] Unknown provider: RestangularProvider <- Restangular <- ctrlAG

javascript,angularjs,restangular

You didn't inject module of 'Restangular' service. Try like this angular.module('AngApp', ['angularGrid','restangular']); ...

Teechart HTML5, line color and thickness

javascript,html5,teechart

Having a Line series: To modify the line thickness, change the series format.stroke.size property. Ie: Chart1.series.items[0].format.stroke.size=2; To modify the series color, change the series format.stroke.fill property. Ie: Chart1.series.items[0].format.stroke.fill="red"; ...

Target next instance of an element/div

javascript,jquery,html

nextAll and first: $(this).nextAll('.hidden').first().slideToggle(...); This question has more about this: Efficient, concise way to find next matching sibling?...

Merge and sum values and put them in an array

javascript,arrays,angularjs,foreach

You cannot store key-value pair in array. Use object to store key-value pair. See comments inline in the code. var obj = {}; // Initialize the object angular.forEach(data, function(value, key) { if (value.start_date > firstdayOfWeek && value.start_date < lastdayOfWeek) { if (obj[value.firstname]) { // If already exists obj[value.firstname] += value.distance;...

Parsing XML array using Jquery

javascript,jquery,xml,jquery-mobile

EMI and CustomerName are elements under json so you can use .find() to find those elements and then text() to get its value. $(data).find("json").each(function (i, item) { var heures = $(item).find("CustomerName").text(); var nbr = $(item).find("EMI").text(); console.log(heures); }); .attr() is used to get the attribute value of an element like in...

Create array from another with specific indices

javascript,arrays

You can use .map, like so var data = [ 'h', 'e', 'l', 'l', 'o', ' ' ]; var indices = [ 4, 0, 5, 0, 1, 2, 2 ]; var res = indices.map(function (el) { return data[el]; }); console.log(res); The map() method creates a new array with the results...

Substring of a file

javascript,arrays,substring

To get your desired output, this will do the trick: var file = "a|b|c|d, a|b|c|d, a|b|c|d, a|b|c|d, a|b|c|d"; var array = file.split(", ") // Break up the original string on `", "` .map(function(element, index){ var temp = element.split('|'); return [temp[0], temp[1], index + 1]; }); console.log(array); alert(JSON.stringify(array)); The split converts...

KnockoutJS custom component loader not executing `loadViewModel`

javascript,knockout.js,requirejs,knockout-components

If you don't "override" the loadComponent method then the default component loader's loadComponent will be invoked which only calls the loadViewModel if you've provided a viewModel config option. In your getConfig method you are returning a config with require which means that your require.js module has to provide the necessary...

Javscript Replace Text in tags without changing children element HTML and Content

javascript,jquery

The way I think you will have to do it is in each element individually and use this jquery small plugin I rewrite here is the code and also fiddle the html <div id="parent"> thisi sthe fpcd <p>p</p> </div> plugin to find the content of the selector text without child...

Google map infowindow position

javascript,google-maps,events,infowindow

Two issues: There is a typo in your click listener code, javascript is case sensitive, infowindow and infoWindow are different objects, so you are not setting the position of the infowindow correctly. infowindow.open(map); infoWindow.setPosition(event.latLng); You are currently placing the infowindow at the place that is clicked infoWindow.setPosition(event.latLng);. If you want...

Setting radio button checked true on button click

javascript,jquery,html

Here is an example : http://jsfiddle.net/xhhLja7m/ $(".choice-option").click(function() { $(this).find('input[type=radio]').prop("checked", "true"); }) ...

Changing interval time to random?

javascript

Assuming the interval is between 1 and 15 seconds and changed after each interval. setIntervsal() does not fit. setTimeout() is here a good choice, because of the single interval of waiting. Every next interval gets a new time to wait and has to be called again. The random waiting time...

Insert data in collection at Meteor's startup

javascript,json,meteor,data,startup

Ok, you'll want to check out Structuring your application. You'll have to make the file with the definition load earlier, or the one with the fixture later. Normally you have your collections inside lib/ and your fixtures inside server/fixtures.js. So if you put your insert code into server/fixtures.js it'll work....

Sockets make no sense?

javascript,node.js,sockets

The client doesn't get to cause arbitrary events to fire on the socket. It is always a message event. Using the same client, try this server code in your connection handler: socket.on('message', function(data) { // data === "pressed", since that's what the client sent console.log("Pressed!"); socket.close(); }); ...

Get elements containing text from array

javascript,jquery,html,arrays,contains

You can use :contains selector. I think you meant either one of those values, in that case var arr = ['bat', 'ball']; var selectors = arr.map(function(val) { return ':contains(' + val + ')' }); var $lis = $('ul li').filter(selectors.join()); $lis.css('color', 'red') <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> <ul> <li>cricket bat</li> <li>tennis ball</li> <li>golf ball</li>...

Onclick add html content and remove it by clicking “delete” link

javascript,jquery

Even though you are using .on() with event delegation syntax, it is not working as the element to which the event is binded is created dynamically. You are registering the handler to col-md-1 which is the parent of the delete button, but that element also is created dynamically so when...

show div only when printing

javascript,html,css

You need some css for that #printOnly { display : none; } @media print { #printOnly { display : block; } } ...

Click on link next link should be display on same page

javascript,php,jquery,html,css3

Ok, so i tried to decypher what you meant with your Question. To Clarify: He has this one page setup. inside the div Our Project, there are two Buttons or links Visit more. When clicked, he wants the About Section to be shown. All in all it is impossible for...

Javascript change the souce of all images present inside a string

javascript,jquery

You can wrap your string into a jQuery-object and use the .find()-method to select the images inside the message-string: var msg = '<span class="user_message">hiiiiiii<img title=":benztip" src="path../files/stickers/1427956613.gif" /><img src="path../files/stickers/416397278.gif" title=":happy" /></span>'; var $msg = $(msg); $msg.find('img').attr('src', 'path_to_img'); $("#chat_content").append($msg); Demo...

submitting form then showing loading image by javascript

javascript,html

Let suppose on button click you are calling ajax method <button onclick="LoadData();"/> before ajax call show image and onComplete ajax method hide this image function LoadData(){ $("#loading-image").show(); $.ajax({ url: yourURL, cache: false, success: function(html){ $("Your div id").append(html); }, complete: function(){ $("#loading-image").hide(); } }); } ...

session value in javascript cannot be set

javascript,function,session

Javascript is a client-side language. Session are server-side component. If you want to update session when user does something on your page, you should create a ajax request to the server. Or maybe use some client side variables that, for some aspects, are similar to session (they will be forever...