I'm getting this error "Uncaught TypeError: Cannot call method 'setBadgeText' of undefined "
This is my code below:
This used to work in Chrome 27.0, but now with Chrome 29.0 it seems to have stopped functioning. I'm not sure if it's this or the.. manifest.json file which loads this in the background.
var DOCLIST_SCOPE = 'https://docs.google.com/feeds';
var DOCLIST_FEED = DOCLIST_SCOPE + '/default/private/full/';
var docs = []; // In memory cache for the user's entire doclist.
var refreshRate = localStorage.refreshRate || 300; // 5 min default.
var pollIntervalMin = 1000 * refreshRate;
var requests = [];
var oauth = ChromeExOAuth.initBackgroundPage({
'request_url': 'https://www.google.com/accounts/OAuthGetRequestToken',
'authorize_url': 'https://www.google.com/accounts/OAuthAuthorizeToken',
'access_url': 'https://www.google.com/accounts/OAuthGetAccessToken',
'consumer_key': 'anonymous',
'consumer_secret': 'anonymous',
'scope': DOCLIST_SCOPE,
'app_name': 'App Name'
});
function setIcon(opt_badgeObj) {
if (opt_badgeObj) {
var badgeOpts = {};
if (opt_badgeObj && opt_badgeObj.text != undefined) {
badgeOpts['text'] = opt_badgeObj.text;
}
if (opt_badgeObj && opt_badgeObj.tabId) {
badgeOpts['tabId'] = opt_badgeObj.tabId;
}
chrome.browserAction.setBadgeText(badgeOpts);
}
};
function clearPendingRequests() {
for (var i = 0, req; req = requests[i]; ++i) {
window.clearTimeout(req);
}
requests = [];
};
function logout() {
docs = [];
setIcon({'text': ''});
oauth.clearTokens();
clearPendingRequests();
};
If your code is based off of the OAuth tutorial,
the problem is most likely due to http://crbug.com/310870, which is a bug in the samples. (The samples worked before because of a bug in Chrome.)
Make sure that any resources in your extension that are part of the OAuth flow are included in the "web_accessible_resources" key of the manifest. In the case of the contacts sample, this fragment needs to be included.
"web_accessible_resources": [
"chrome_ex_oauth.html",
"chrome_ex_oauthsimple.html"
],
Related
I am using prosemirror to build a collaborative editor, where multiple people can edit one document. I wrote the following code, based on the example given here - http://prosemirror.net/docs/guides/collab/
Here is the code-
const { EditorState } = require('prosemirror-state');
const { EditorView } = require('prosemirror-view');
const { DOMParser } = require("prosemirror-model");
const {schema} = require("./schema");
var collab = require("prosemirror-collab");
function Authority(doc) {
this.doc = doc
this.steps = []
this.stepClientIDs = []
this.onNewSteps = []
}
Authority.prototype.receiveSteps = function(version, steps, clientID) {
if (version != this.steps.length) return
var self = this
// Apply and accumulate new steps
steps.forEach(function(step) {
self.doc = step.apply(self.doc).doc
self.steps.push(step)
self.stepClientIDs.push(clientID)
})
// Signal listeners
this.onNewSteps.forEach(function(f) { f() })
}
Authority.prototype.stepsSince = function(version) {
return {
steps: this.steps.slice(version),
clientIDs: this.stepClientIDs.slice(version)
}
}
var auth = new Authority('');
collabEditor(auth)
function collabEditor(authority) {
var view = new EditorView(document.querySelector("#editor"), {
state: EditorState.create({schema: schema, plugins: [collab.collab()]}),
dispatchTransaction: function(transaction) {
var newState = view.state.apply(transaction)
view.updateState(newState)
var sendable = collab.sendableSteps(newState)
if (sendable)
authority.receiveSteps(sendable.version, sendable.steps,
sendable.clientID)
}
})
authority.onNewSteps.push(function() {
var newData = authority.stepsSince(collab.getVersion(view.state))
view.dispatch(
collab.receiveTransaction(view.state, newData.steps, newData.clientIDs))
})
return view
}
When i run this code (after installing all the dependencies and setting up a simple server in nodejs) I am basically able to edit a text box but I am not able to open two tabs in chrome and see the collaboration happen. What am i doing wrong?
Will love some feedback.
This is the example code for a simple, single-page, no-external-communication setup. As such, no, it won't communicate to other tabs. For that, you'd have to move the authority somewhere else and set up pages to actually communicate with it over HTTP or websockets. (See for example this demo.)
dear all.
We have crypto signing extensions implemented for few browsers in our application, everything went fine, but now we faced problem with new Mozilla's multiprocess API migration (E10S aka Electrolysis).
Our web part interacts with extension which collaborates with native library written in C (we utilize c-types lib for this part).
Now Firefox is moving to multiprocess model that requires code adaptation. The most significant and complicated part for now is content-to-extension communication reimplementation. It was implemented according to related official documentation
We used bootstrap extension initialization in following manner:
function startup(params, reason) {
include("chrome/content/extmain.js");
mainWindow = winMediator.getMostRecentWindow("navigator:browser");
if (null == mainWindow) {
var windowListenerWidget = {
onOpenWindow: function (aWindow) {
winMediator.removeListener(windowListenerWidget);
var mainWindow = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindow);
mainWindow.addEventListener("load", function onWindowLoad() {
mainWindow.removeEventListener("load", onWindowLoad);
addAddonListener(mainWindow);
});
},
onCloseWindow: function (aWindow) {
},
onWindowTitleChange: function (aWindow, aTitle) {
}
};
winMediator.addListener(windowListenerWidget);
} else {
addAddonListener(mainWindow);
}
}
function addAddonListener(win) {
win.document.addEventListener(
"CryptoApiExtension_HandleMsg",
function (event) {
var node = event.target;
if (!node || node.nodeType != 3) {
return;
}
var response = CryptoApiExtension.handleMessage(JSON.parse(node.nodeValue));
var doc = node.ownerDocument;
node.nodeValue = JSON.stringify(response);
var event = doc.createEvent("HTMLEvents");
event.initEvent("CryptoApiExtension_response", true, false);
return node.dispatchEvent(event);
}, false, true);
}
This code above was broken with new multiprocess architecture. There are lot of documentation we have read, but still there's no way we could handle this issue.
The question is: how to adapt this code to make extension accept web page invocations?
You now need to use messageManagers and frame scripts for inter-process communication:
// bootstrap.js
function addAddonListener(win) {
win.messageManager.addEventListener(
"CryptoApiExtension_request",
function (event) {
var response = CryptoApiExtension.handleRequest(event.json);
var childMM = event.target.messageManager;
childMM.sendAsyncMessage("CryptoApiExtension_response", response);
}
);
// <...>
win.messageManager.loadFrameScript("chrome://myaddon/content/frame-script.js", true);
}
// frame-script.js
sendAsyncMessage("CryptoApiExtension_request", request);
addMessageListener(
"CryptoApiExtension_response",
function(event) {
handleResponse(event.json);
}
);
I log client-side errors thrown by my application and have been seeing the following error occurring infrequently, but consistently, in a production environment. I'm assuming it's not a fluke or a PC in a bad state, but I am unable to reproduce it locally.
Uncaught SyntaxError: Unexpected token <
It is being thrown by YouTube's iframe API located here: https://www.youtube.com/iframe_api. That is, the Error objects URL specifically indicates that it is this source and not www-widgetapi.
This error is confusing me because the token < is only referenced once, inside a for loop, and it's perfectly valid syntax.
Does anyone have any ideas on what might be occurring?
I simply inject the script using jQuery:
if (this.get('inserted')) {
Backbone.Wreqr.radio.channel('error').commands.trigger('log:message', 'API script already inserted');
return;
}
// This function will be called when the API is fully loaded. Needs to be exposed globally so YouTube can call it.
window.onYouTubeIframeAPIReady = this._onYouTubeIframeAPIReady.bind(this);
$('<script>', {
src: 'https://www.youtube.com/iframe_api',
}).insertBefore($('script:first'));
this.set('inserted', true);
Here's the beautified version of their script:
if (!window['YT']) {
var YT = {
loading: 0,
loaded: 0
};
}
if (!window['YTConfig']) {
var YTConfig = {
'host': 'http://www.youtube.com'
};
}
if (!YT.loading) {
YT.loading = 1;
(function() {
var l = [];
YT.ready = function(f) {
if (YT.loaded) {
f();
} else {
l.push(f);
}
};
window.onYTReady = function() {
YT.loaded = 1;
for (var i = 0; i < l.length; i++) {
try {
l[i]();
} catch (e) {}
}
};
YT.setConfig = function(c) {
for (var k in c) {
if (c.hasOwnProperty(k)) {
YTConfig[k] = c[k];
}
}
};
var a = document.createElement('script');
a.id = 'www-widgetapi-script';
a.src = 'https:' + '//s.ytimg.com/yts/jsbin/www-widgetapi-vflBfDu58/www-widgetapi.js';
a.async = true;
var b = document.getElementsByTagName('script')[0];
b.parentNode.insertBefore(a, b);
})();
}
I have a similar question here, but I thought I'd ask it a different way to cast a wider net. I haven't come across a workable solution yet (that I know of).
I'd like for XCode to issue a JavaScript command and get a return value back from an executeSql callback.
From the research that I've been reading, I can't issue a synchronous executeSql command. The closest I came was trying to Spin Lock until I got the callback. But that hasn't worked yet either. Maybe my spinning isn't giving the callback chance to come back (See code below).
Q: How can jQuery have an async=false argument when it comes to Ajax? Is there something different about XHR than there is about the executeSql command?
Here is my proof-of-concept so far: (Please don't laugh)
// First define any dom elements that are referenced more than once.
var dom = {};
dom.TestID = $('#TestID'); // <input id="TestID">
dom.msg = $('#msg'); // <div id="msg"></div>
window.dbo = openDatabase('POC','1.0','Proof-Of-Concept', 1024*1024); // 1MB
!function($, window, undefined) {
var Variables = {}; // Variables that are to be passed from one function to another.
Variables.Ready = new $.Deferred();
Variables.DropTableDeferred = new $.Deferred();
Variables.CreateTableDeferred = new $.Deferred();
window.dbo.transaction(function(myTrans) {
myTrans.executeSql(
'drop table Test;',
[],
Variables.DropTableDeferred.resolve()
// ,WebSqlError
);
});
$.when(Variables.DropTableDeferred).done(function() {
window.dbo.transaction(function(myTrans) {
myTrans.executeSql(
'CREATE TABLE IF NOT EXISTS Test'
+ '(TestID Integer NOT NULL PRIMARY KEY'
+ ',TestSort Int'
+ ');',
[],
Variables.CreateTableDeferred.resolve(),
WebSqlError
);
});
});
$.when(Variables.CreateTableDeferred).done(function() {
for (var i=0;i < 10;i++) {
myFunction(i);
};
Variables.Ready.resolve();
function myFunction(i) {
window.dbo.transaction(function(myTrans) {
myTrans.executeSql(
'INSERT INTO Test(TestID,TestSort) VALUES(?,?)',
[
i
,i+100000
]
,function() {}
,WebSqlError
)
});
};
});
$.when(Variables.Ready).done(function() {
$('#Save').removeAttr('disabled');
});
}(jQuery, window);
!function($, window, undefined) {
var Variables = {};
$(document).on('click','#Save',function() {
var local = {};
local.result = barcode.Scan(dom.TestID.val());
console.log(local.result);
});
var mySuccess = function(transaction, argument) {
var local = {};
for (local.i=0; local.i < argument.rows.length; local.i++) {
local.qry = argument.rows.item(local.i);
Variables.result = local.qry.TestSort;
}
Variables.Return = true;
};
var myError = function(transaction, argument) {
dom.msg.text(argument.message);
Variables.result = '';
Variables.Return = true;
}
var barcode = {};
barcode.Scan = function(argument) {
var local = {};
Variables.result = '';
Variables.Return = false;
window.dbo.transaction(function(myTrans) {
myTrans.executeSql(
'SELECT * FROM Test WHERE TestID=?'
,[argument]
,mySuccess
,myError
)
});
for (local.I = 0;local.I < 3; local.I++) { // Try a bunch of times.
if (Variables.Return) break; // Gets set in mySuccess and myError
SpinLock(250);
}
return Variables.result;
}
var SpinLock = function(milliseconds) {
var local = {};
local.StartTime = Date.now();
do {
} while (Date.now() < local.StartTime + milliseconds);
}
function WebSqlError(tx,result) {
if (dom.msg.text()) {
dom.msg.append('<br>');
}
dom.msg.append(result.message);
}
}(jQuery, window);
Is there something different about XHR than there is about the executeSql command?
Kind of.
How can jQuery have an async=false argument when it comes to Ajax?
Ajax, or rather XMLHttpRequest, isn't strictly limited to being asynchronous -- though, as the original acronym suggested, it is preferred.
jQuery.ajax()'s async option is tied to the boolean async argument of xhr.open():
void open(
DOMString method,
DOMString url,
optional boolean async, // <---
optional DOMString user,
optional DOMString password
);
The Web SQL Database spec does also define a Synchronous database API. However, it's only available to implementations of the WorkerUtils interface, defined primarily for Web Workers:
window.dbo = openDatabaseSync('POC','1.0','Proof-Of-Concept', 1024*1024);
var results;
window.dbo.transaction(function (trans) {
results = trans.executeSql('...');
});
If the environment running the script hasn't implemented this interface, then you're stuck with the asynchronous API and returning the result will not be feasible. You can't force blocking/waiting of asynchronous tasks for the reason you suspected:
Maybe my spinning isn't giving the callback chance to come back (See code below).
I should mention up front I'm new to code/stackoverflow so my apologies if this question doesn't makes sense. I'm beyond stumped, I'm trying to build a chrome extension that saves the ip address, url and a server finger print. The serverfingerprint is a field that lives within the response headers. Using my background.js and localStorage I can save this information and then display it in my pop up window. This is all fine and dandy except I can't figure out how to save it on a per tab basis, aka... if I have 5 tabs open, I'd like to click my extension and have it display the url for each corresponding tab. example: click tab4 and shows tab4's url, then click tab2 and it shows the url of tab2.
the below code works except for it doesn't tie to the tabId so it's not exactly ideal. Any ideas of where to start researching would be very appreciated!
what i've done thus far:
background.js:
chrome.experimental.webRequest.onCompleted.addListener(function (details)
{
var headers = details.responseHeaders;
localStorage['ip'] = details.ip;
localStorage['url'] = details.url;
for (var i = 0, length = headers.length; i < length; i++)
{
var header = headers[i];
if (header.name == 'X-Server-Fingerprint')
{
localStorage['XServerFingerprint'] = header.value.toString();
break;
}
}
},{'urls': ['http://www.someurl.com/*']},['responseHeaders']);
popup.js:
document.getElementById('url').innerText = localStorage['url'];
document.getElementById('ip').innerText = localStorage['ip'];
document.getElementById('XServerFingerPrint').innerText = localStorage['XServerFingerPrint'];
As each tab has unique id (until browser restart), you can use it to identify tabs.
You are probably interested only in current tabs, which makes things simpler as you don't need localStorage for this (which persists data between browser restarts). Just use background page's namespace to store data about all tabs:
// background.js
var tabs = {}; //all tab data
chrome.experimental.webRequest.onCompleted.addListener(function (details)
{
var tabInfo = {};
tabInfo["ip"] = ...;
tabInfo["url"] = ...;
tabInfo["XServerFingerprint"] = ...;
tabs[details.tabId] = tabInfo;
}
// popup.js
chrome.tabs.getSelected(null, function(tab){
var tabInfo = chrome.extension.getBackgroundPage().tabs[tab.id]; // get from bg page
document.getElementById('url').innerText = tabInfo['url'];
document.getElementById('ip').innerText = tabInfo['ip'];
document.getElementById('XServerFingerPrint').innerText = tabInfo['XServerFingerPrint'];
});
If you do need localStorage then you can convert tabs object to json string and store it there.
Ok, so I've sorted out my issues! Well the ones concerning chrome extensions haha, which appears to be pretty much exactly what Serg is saying (thx Serg!!) I wrote it a bit different tho.
// background.js
chrome.experimental.webRequest.onCompleted.addListener(function (details)
{
var headers = details.responseHeaders;
var tabId = details.tabId;
var ip = details.ip;
var url = details.url;
for (var i = 0, length = headers.length; i < length; i++) {
var header = headers[i];
//custom field in response headers from my site
if (header.name == 'X-Server-Fingerprint') {
var XServerFingerprint = header.value.toString();
var data = {
ip: ip,
url: url,
fingerprint: XServerFingerprint
}
//store it
localStorage[tabId] = JSON.stringify(data);
break;
}
}
},{'urls': ['http://www.corbisimages.com/*']},['responseHeaders']);
}
// and then on my popup.js
chrome.tabs.getSelected(null, function(tab) {
var parseData = JSON.parse(localStorage[tab.id]);
document.getElementById('XServerFingerprint').innerText = parseData.fingerprint;
document.getElementById('url').innerText = parseData.url;
document.getElementById('ip').innerText = parseData.ip;
});