I am trying to develop a form abandonment heat mapper
function newMarkup(id, uniqueHits){
var min = Math.min.apply(null,uniqueHits);
var max = Math.max.apply(null,uniqueHits);
var med = max / 2;
for(var num = 0; num < id.length; num++){
styleElement(id[num], uniqueHits[num], min, max, med);
}}
function styleElement(element, value, min, max, med){
var el = $("[id$=" + element + "]");
if(el.prop('nodeName') === "INPUT"){
if(value == max){
el.addClass('very-good');
}
if(value < max && value > med){
el.addClass('good');
}
if(value == med){
el.addClass('average');
}
if(value < med && value > min){
el.addClass('not-so-good');
}
if(value == min){
el.addClass('poor');
}
} else {
el = el.next();
if(value == max){
el.addClass('very-good');
}
if(value < max && value > med){
el.addClass('good');
}
if(value == med){
el.addClass('average');
}
if(value < med && value > min){
el.addClass('not-so-good');
}
if(value == min){
el.addClass('poor');
}
}
}
and I am wondering if it is possible to do the call to the api from a chrome extension?
Essentially I am trying to do this call to get the data:
gapi.client.analytics.data.ga.get({
'ids': 'ga:' + profileId,
'start-date': '7daysAgo',
'end-date': 'today',
'metrics': 'ga:uniqueEvents',
'dimensions': 'ga:eventLabel',
'sort':'-ga:uniqueEvents',
'filters': "ga:eventCategory==Form Field Tracking - /join"
})
I tried do create my heatmapper by having an iFrame in an MVC web application but because of the trouble of trying to send data across domains, I gave up on that.
I would like to know if it's possible to get data from the analytic's API from a chrome extension? I'd imagine it would have to be done in a similar fashion as how google scripts uses the analytics API (using a service account) but I have been unable to find any documentation or find out if this is even possible.
(Example of code in scripts)
function runReport(profileId) {
var today = new Date();
var oneWeekAgo = new Date(today.getTime() - 7 * 24 * 60 * 60 * 1000);
var startDate = Utilities.formatDate(oneWeekAgo, Session.getTimeZone(), 'yyyy-MM-dd');
var endDate = Utilities.formatDate(today, Session.getTimeZone(), 'yyyy-MM-dd');
var tableId = 'ga:' + profileId;
var metric = 'ga:uniqueEvents';
var options = {
'dimensions': 'ga:eventLabel',
'sort':'-ga:uniqueEvents',
'filters': "ga:eventCategory==Form Field Tracking - /join"
};
var report = Analytics.Data.Ga.get(tableId, startDate, endDate, metric, options);
}
I'd really appreciate any help or advice anyone has for me. I am trying to query the google analytic's API from a chrome extension. Is this possible?
Not tested on GA specifically but this is the general method of working with scripts that require external server for the API:
The content script can't make requests to other sites so it should ask the background page to do it by sending a message
The background page includes ga.js script referenced in the manifest, this file must be present in the extension, it's not a remotely loaded script.
The background page can communicate with the external API server after we add the corresponding CSP rule (added in the manifest)
Now the message from step 1 is received by the background page listener, which invokes GA and sends the results back to the content script of the original tab (tabId was saved when the first message was received).
manifest.json:
"content_scripts": [
{
"matches": ["<all_urls>"],
"run_at": "document_start",
"all_frames": true,
"js": ["content.js"]
}
],
"background": {
"scripts": ["background.js", "ga.js"]
},
"content_security_policy":
"script-src 'self' https://ssl.google-analytics.com; object-src 'self'",
.............
content.js:
chrome.runtime.sendMessage({type: "getGA", data: some_data_for_GA});
chrome.runtime.onMessage.addListener(function(msg) {
if (msg.type == "GA") {
// apply msg.data to the page elements
...................
}
});
background.js:
chrome.runtime.onMessage.addListener(function(msg, sender, sendResponse) {
var tabId = sender.tab.id, frameId = sender.frameId;
if (msg.type == "getGA") {
gapi.client.analytics.data.ga.get({
..................... // use msg.data if needed
}).execute(function(response) {
sendMessageToFrameId(tabId, frameId, {type: "GA", data: response});
});
}
});
function sendMessageToFrameId(tabId, frameId, msg) {
// 1. frameId works since Chrome 41 and throws on prior versions
// 2. without frameId Chrome 45 sends the message to wrong tabs
try { chrome.tabs.sendMessage(tabId, msg, {frameId: frameId}); }
catch(e) { chrome.tabs.sendMessage(tabId, msg); }
}
Related
I'm trying to create chrome extension which check if site contains specific element, then clear cookies for this site and refresh.
I created sample extension to delete cookies but in background.js using event chrome.browserAction.onClicked.addListener, :
chrome.browserAction.onClicked.addListener(function(tab) {
var url = tab.url;
var matches = url.match(/^https?\:\/\/([^\/?#]+)(?:[\/?#]|$)/i);
var d = matches && matches[1].replace('www.','');
d = '.'+d;
chrome.cookies.getAll({domain: d}, function (cookies) {
for (var i=0; i<cookies.length; i++) {
var url = "http" + (cookies[i].secure ? "s" : "") + "://" + cookies[i].domain + cookies[i].path;
var cname = cookies[i].name;
chrome.cookies.remove({
"url": url,
"name": cname
});
}
chrome.tabs.reload();
});
});
I took this code from one of posts on stackoverflow, and I was trying to transform it for my need.
In my main extension in background.js I have:
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
chrome.tabs.getSelected(null, function(tab){
chrome.tabs.executeScript(null, {file: 'script.js'});
});
});
and then in script.js:
..some code...
var test = document.getElementById('u_0_c');
if (test === null || test.innerText == "") {
/*------------------------------*/
HERE I WANT TO CLEAR COOKIES
/*----------------------------*/
}
..some code...
I can't use there my code to clear cookies because I got errors like:
Cannot read property 'getSelected' of undefined and similiars.
Thanks for every help ;)
I am writing a chrome extension to block certain pages on a website.
I do this by loading a .txt file full of the pages to be blocked and then comparing each to the url loaded by the user and then redirecting to a blocking page if the url matches any in the file. However, everything works apart from the actual redirect.
manifest.json
{
"name": "Reddit Subreddit Blocker",
"description": "Blocks access to specified subreddits.",
"version": "1.0",
"manifest_version": 2,
"background": {
"scripts":["background.js"],
"pages": ["blocked.html"],
"persistent": true
},
"permissions": [
"webRequest",
"*://*.reddit.com/r/*",
"webRequestBlocking"
]
}
background.js
chrome.webRequest.onBeforeRequest.addListener(
function(details) {
var r = new XMLHttpRequest();
r.open("GET", chrome.extension.getURL("test.txt"), true);
r.onreadystatechange = function(e){
if (r.readyState == 4 && r.status == 200){
var subreddits = r.responseText.split("\n");
var index;
var url = details.url;
var found = false;
for (index = 0; index < subreddits.length && found == false; ++index){
if (subreddits[index] === url){
console.log("Subreddit found.");
found = true;
}
}
if (found == false){
console.log("not found");
return {cancel: false};
}else{
console.log("redirecting");
return {redirectUrl: chrome.extension.getURL("blocked.html")};
}
}
};
r.send(null);
}, {
urls: ["https://*.reddit.com/r/*"]
}, ["blocking"]
);
The urls to be blocked are stored on seperate lines in the .txt file.
When I run the code with a url that should be blocked, I simply get the output:
Subreddit found.
redirecting
Therefore, the subreddit was found and the if statement to redirect was executed but it was not actually redirected.
I am (trying to) implementing a Chrome Extension, that uses the Tumblr API. For that to work I need to authorize via OAuth (1.0a).
I managed to get most of the authorization to work but I think I am missing something...
My manifest.json of the Chrome Extension I am writing looks like this for now:
{
"name": "Tumblr - Tiled Dashboard",
"version": "0.1.1",
"manifest_version": 2,
"description": "This extension modifies the look of your Tumblr dashboard.",
"icons": {
"16": "images/icon_16.png",
"48": "images/icon_48.png",
"128": "images/icon_128.png"
},
"background": {
"page": "background.html"
},
"content_scripts": [
{
"matches": [ "*://*.tumblr.com/dashboard" ],
"css": [ "styles.css" ],
"js": [ "jquery-2.1.3.min.js", "masonry.min.js", "code.js" ]
}
],
"permissions": [
"https://www.google-analytics.com/",
"https://api.tumblr.com/v2/*",
"webRequest",
"storage",
"tabs",
"https://www.google.com/accounts/OAuthGetRequestToken", "https://www.google.com/accounts/OAuthAuthorizeToken", "https://www.google.com/accounts/OAuthGetAccessToken"
],
"web_accessible_resources": [ "chrome_ex_oauth.html", "injectedCode.js" ],
"content_security_policy": "script-src 'self' https://api.tumblr.com/v2/ https://ssl.google-analytics.com; object-src 'self'",
"homepage_url": "http://desvre.tumblr.com/",
"author": "Franz Spitaler"
}
...I think this should be ok. In my background.html there are in fact only the included scripts (google analytics and the three oauth files I got from here: https://developer.chrome.com/extensions/tut_oauth . Those three files are also included in the fourth file I downloaded from the previous source ("chrome_ex_oauth.html").
Now when I reload the Chrome Extension in the Extensions (Ctrl + r) the Redirecting page opens and redirects me to the Tumblr authorization page, where I can allow the access.
Since I also added the "chrome_ex_oauth.html" to the "web_accessible_resources" in the manifest.json this works.
The problem occurs after the click on the 'allow' button. I simply get back to the redirecting page ("chrome_ex_oauth.html") and nothing more happens. When I open up the console, I can see an error message like the following:
GET https://www.tumblr.com/oauth/access_token?oauth_consumer_key=MY_CONSUMER_KEY&oauth_nonce=D3VeV&oauth_signature=kvhL%2F9GSMuiODoPR%2FyUrUiqzqF0%3D&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1424250463&oauth_token=6khqzjiMFbM7hcqqnNf8hm9ttDELKUVYo2TBQmyLOtepGN9KhJ&oauth_verifier= 400 (Bad Request)
As described in the OAuth tutorial page from Google I use this to initialize the 'background page' (which leads to the error message):
var oauth = ChromeExOAuth.initBackgroundPage({
'request_url': 'https://www.tumblr.com/oauth/request_token',
'authorize_url': 'https://www.tumblr.com/oauth/authorize',
'access_url': 'https://www.tumblr.com/oauth/access_token',
'consumer_key': 'MY_CONSUMER_KEY',
'consumer_secret': 'MY_SECRET_CONSUMER_KEY',
'app_name': 'Tumblr Tiled Dashboard'
});
Did I miss something important here? I think the manifest.json file is ok (permissions, web_accessible_resources?!).
Thank you for any help. There is really no really great tutorial for OAuth out there for Google Extensions (except that linked page)...
As #abraham pointed out, there was a missing parameter, as seen in my posted error.
I was able to track down the problem and found it in the function of the chrome_ex_oauth.js file. I changed the function from:
ChromeExOAuth.formDecode = function(encoded) {
var params = encoded.split("&");
var decoded = {};
for (var i = 0, param; param = params[i]; i++) {
var keyval = param.split("=");
if (keyval.length == 2) {
var key = ChromeExOAuth.fromRfc3986(keyval[0]);
var val = ChromeExOAuth.fromRfc3986(keyval[1]);
decoded[key] = val;
}
}
return decoded;
};
to this:
ChromeExOAuth.formDecode = function(encoded) {
var params = encoded.split("&");
var decoded = {};
for (var i = 0, param; param = params[i]; i++) {
var keyval = param.split("=");
if (keyval.length == 2) {
var key = ChromeExOAuth.fromRfc3986(keyval[0]);
var val = ChromeExOAuth.fromRfc3986(keyval[1]);
decoded[key] = val;
}
else if (keyval.length == 3){
var key = ChromeExOAuth.fromRfc3986(keyval[0]);
var val = ChromeExOAuth.fromRfc3986(keyval[1].split("#")[0]);
decoded[key] = val;
}
}
return decoded;
};
Where the last parameter was not identified correctly because the ending of the url I got looks like this: #_=_
With the keyval[1].split('#')[0] I get the exact part of the parameter, that I need!
Thank you for the help, everything seems to work now. A request that needs OAuth authorization did, at least!
My issue of concern is to find out the possible mistakes in my code which might hamper the working of opentok services to run smoothly(without any error) in my code. There something might be going wrong with my code. Please examine How Am I ending any video chat through my code.And other codes might have been written incorrectly
The library version I'm using is this
<script type="text/javascript" src="http://static.opentok.com/webrtc/v2.2/js/TB.min.js" ></script>
I'm using dot net sdk to generate sessionId and tokens on server side
I have published my application online , and it runs well 30 % time but 70% time it throws errors like sessionInfoError or many other errors
Api key secret and other settings aremade in web.config file like this
<appSettings>
<add key="opentok_key" value="******"/>
<add key="opentok_secret" value="***********************"/>
<add key="opentok_server" value="https://api.opentok.com"/>
<add key="opentok_token_sentinel" value="T1=="/>
<add key="opentok_sdk_version" value="tbdotnet"/>
Rest of the code and functions written with the help of tokbox documentation are like this
var sessionId;
var token;
var apiKey = "*******";
var publisher_connections = {};
var publisher;
var session;
var Id;
var streamedTime;
var hours;
var minutes;
var seconds;
function a() {
sessionId = document.getElementById('<%= hdn.ClientID%>').value;
token = document.getElementById('<%= hdn1.ClientID%>').value;
session = TB.initSession(sessionId);
session.addEventListener("sessionConnected", sessionConnectedHandler);
session.addEventListener('sessionDisconnected', sessionDisconnectedHandler);
session.addEventListener("streamCreated", streamCreatedHandler);
session.addEventListener("sessionDestroyed", sessionDestroy);
session.addEventListener("signal", signalHandler);
session.addEventListener("streamDestroyed", streamDestroyedHandler);
session.addEventListener('connectionCreated', connectionCreatedHandler);
session.addEventListener('connectionDestroyed', connectionDestroyedHandler);
TB.addEventListener("exception", exceptionHandler);
TB.setLogLevel(TB.DEBUG);
session.connect(apiKey, token);
}
function sessionConnectedHandler(event) {
console.log("connected");
subscribeToStreams(event.streams);
session.publish();
}
function sessionDisconnectedHandler(event) {
alert("Session Disconnected");
for (var i = 0; i < event.streams.length; i++) {alert(event.streams[i].connection.connectionId);
delete publisher_connections[event.streams[i].connection.connectionId];
}
publisher = null;
}
function streamCreatedHandler(event) {
console.log("created");
subscribeToStreams(event.streams);
for (var i = 0; i < event.streams.length; i++) {
publisher_connections[event.streams[i].connection.connectionId] = 1;
}
}
function subscribeToStreams(streams) {
for (var i = 0; i < streams.length; i++) {
var stream = streams[i];
if (stream.connection.connectionId != session.connection.connectionId) {
var subscriber = session.subscribe(stream);
if (stream.connection.data == "accept") {
alert(stream.connection.data + " Joined You");
startTimer();
}
else {
alert(stream.connection.data + " Joined You");
UpdateInitializedTime();
startTimer();
}
}
}
}
function exceptionHandler(event) {
alert(event.message);
}
function sessionDestroy(event) {
session.disconnect();
alert("Session Destroyed");
}
}
function streamDestroyedHandler(event) {
for (var i = 0; i < event.streams.length; i++) {
delete publisher_connections[event.streams[i].connection.connectionId];
//alert("Someone left you");
}
}
function connectionDestroyedHandler(event) {
alert(event.streams[i].connection.connectionId + " left the conversation");
// This signals that connections were destroyed
}
function connectionCreatedHandler(event) {
// This signals new connections have been created.
// alert("this");
// alert(connection.data);
}
There is a setInterval function which calls itself every second and will end video chat when fixed time become 00:00:00
function timeOver(){
if (hours == 00 && minutes == 00 && seconds == 00) {
session.disconnect();
alert("Time Given For this Video Chat is Over");
}
}
I have a button for disconnecting from session
<input type="button" value="Disconnect" id="btnDisconnect" onclick="sessionDestroy()" />
it calls the sessionDestroy() function on clicking
Please examine these codes like a doctor
You code looks alright. Please keep in mind that Stack Overflow is used to ask questions and solve bugs. Using it as a place to proofread your code is not the intended idea.
Getting some odd behavior from google custom search that I can't seem to suss out. Maybe someone has a clue.
I'm putting together a Magento site, which has its own internal search engine - but is limited to product only. I want to implement google custom search results on the search results page as well. I figure I should be able to simply execute a search based on the query vars in the url (to return all the non-product content), as such:
<section style="min-height:600px">
<div style="background-color:#DFDFDF; min-height:800px; width:100%;">
<div id="cse">Loading</div>
</div>
<script src="http://www.google.com/jsapi" type="text/javascript"></script>
<script type="text/javascript">
//<![CDATA[
$(document).ready( function(){
console.log('search initiated');
var t = window.setTimeout( function(){ customSearch(); }, 5000 );
});
function customSearch(){
var q = urlParams()['q'];
if (q != undefined && q != ""){
console.log('q : %s', q); //outputs successfully
google.load('search', '1');
google.setOnLoadCallback(function () {
var customSearchControl = new google.search.CustomSearchControl(MY CUSTOM ID KEY);
var cseDrawOptions = new google.search.DrawOptions();
cseDrawOptions.setAutoComplete(true); //unknown if this is required...
customSearchControl.draw('cse',cseDrawOptions);
customSearchControl.execute(q);
}, true);
}
}
function urlParams(){
var vars = [];
var hash;
var index = window.location.href.indexOf('?');
if( index != -1 ){
var hashes = window.location.href.slice(index + 1).split('&');
for(var i = 0; i < hashes.length; i++){
hash = hashes[i].split('=');
vars.push(hash[0]);
vars[hash[0]] = hash[1].replace(/\+/g, " ");
}
}
return vars;
}
//]>
</script>
</section>
I'll note that I've pulled all other content out of the logic (but its implementation in magento is identical).
So the behavior goes like this: page loads fine (I'm delaying the google search with a timeout for testing purposes ). Assuming there is a query var in the url the console traces out as expected. Then the page just gets wiped out, with no content back from google. "Wiped out"... meaning all elements on teh page disappear, or are getting overwritten by a new page that google loads. As if the search control isn't creating an iframe - its just replacing the page with a <body>-less html page.
I've ready a number of articles on the subject, and gone over the API - this code looks like it should work. But clearly isn't.
What am I missing?
Cheers -
UPDATE
Continued messing around with this has revealed that for whatever reason :
google.load('search', '1');
google.google.setOnLoadCallback( console.log('loaded') )
Was the cause of the replaced page issue. The responded page, however contained links to the search module that google is hosting. And if I manually linked those files (forgoing a google.load) then I could run a search as expected:
<script src="http://www.google.com/jsapi" type="text/javascript"></script>
<script src="http://www.google.com/uds/?file=search&v=1" type="text/javascript"></script>
<script type="text/javascript">
//<![CDATA[
... search logic
Then I found an alternate syntax on the google developers page that seemed to work as expected:
$(document).ready( function(){
google.load("search", "1", {"callback" : customSearch});
});
function customSearch(){
var q = urlParams()['q'];
if (q != undefined && q != ""){
var cseControl = new google.search.CustomSearchControl('MY CUSTOM KEY');
var cseDrawOptions = new google.search.DrawOptions();
cseDrawOptions.enableSearchResultsOnly()
cseControl.draw('cse', cseDrawOptions);
cseControl.execute(q);
}
}
Which works as expected. Only real problem at this point is the host of
Unsafe JavaScript attempt to access frame with URL http://mydomain from frame with URL http://www.google/cse?...
That now gets thrown.
I don't know how the two different versions of load syntax changes anything... but it seemed to of. Whatever the case, I'm unclear as to how to resolve these cross domain errors.
Thoughts would be great.
Nothin huh?
Well - I've basically worked out a good solution, using an alternate method that I think will be more flexible in the long run. Using googles RESTful API and simple jquery .ajax call, I can obtain good, controllable results with no cross-domain errors:
<div id="cse">Loading</div>
<script>
//https://developers.google.com/custom-search/v1/getting_started
//https://developers.google.com/custom-search/v1/using_rest#query-params
//https://developers.google.com/custom-search/v1/cse/list
var _url = "https://www.googleapis.com/customsearch/v1";
var _key = 'AIzaSy... your api key here';
var _cx = '001809... your engine id';
var _q = urlParams()['q']; //query param
jQuery(document).ready(function() {
$j.ajax({
url : _url,
type : 'GET',
dataType : 'jsonp',
data :{
key : _key,
cx : _cx,
q :_q
},
success : function(data, textStatus, jqXHR){ responseHandler(data); },
error : function(jqXHR, textStatus, errorThrown){ console.log('error: %s'), errorThrown},
beforeSend : function(){ console.log('sending request')},
crossDomain : true
});
});
function responseHandler( response, status) {
console.log(response);
var cse = $j('#cse'); // render vars as needed...
for (var i = 0; i < response.items.length; i++) {
var item = response.items[i];
cse.append( "<br>" + item.htmlTitle);
}
}
function urlParams(){
var vars = [];
var hash;
var index = window.location.href.indexOf('?');
if( index != -1 ){
var hashes = window.location.href.slice(index + 1).split('&');
for(var i = 0; i < hashes.length; i++){
hash = hashes[i].split('=');
vars.push(hash[0]);
vars[hash[0]] = hash[1];
}
}
return vars;
}
</script>
And you can too;D
Cheers