I am developing (trying) a firefox extension to intercept HTTP 500 responses status code and cancel the original request and sending it with another custom protocol.
I am trying to implement and observer and a listener but it is not working for me. I am new in this and I am sure that I am doing something wrong. Can anyone help me to figure out how to do this.
I followed the http://www.softwareishard.com/blog/firebug/nsitraceablechannel-intercept-http-traffic/ tutorial and It is not working, maybe I am not binding or using the component in the correct manner.
My code is:
Chrome.manifest
content lightweightandsecureprotocol chrome/content/
content lightweightandsecureprotocol chrome/content/ contentaccessible=yes
locale lightweightandsecureprotocol en-US crhome/locale/en-US/
skin lightweightandsecureprotocol classic/1.0 chrome/skin/
style chrome://global/content/customizeToolbar.xul chrome://lightweightandsecureprotocol/skin/browser.css
overlay chrome://browser/content/browser.xul chrome://lightweightandsecureprotocol/content/browser.xul
component {90b7bac4-78fc-4193-a2d9-1ed7a4f675eb} components/HttpResponseObserver.js
Source Code :
/chrome/content/Browser.xul
<?xml version="1.0"?>
<?xml-stylesheet type="text/css"
href="chrome://lightweightandsecureprotocol/skin/browser.css"?>
<overlay id="overlay"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/x-javascript" src="chrome://lightweightandsecureprotocol/components/HttpResponseObserver.js"/>
<script>
try{
var myComponent = Components.classes['#patricia.figueroa.millan/httpresponseobserver;1']
.getService().wrappedJSObject;
}catch(anError){
dump("ERROR:" + anError);
}
</script>
</overlay>
Source Code:
/components/HttpResponseObserver.js
const nsISupports = Components.interfaces.nsISupports;
const CLASS_ID = Components.ID("90b7bac4-78fc-4193-a2d9-1ed7a4f675eb");
const CLASS_NAME = "Http Response Observer";
const CONTRACT_ID = "#patricia.figueroa.millan/httpresponseobserver;1";
function HttpResponseObserver() {
this.wrappedJSObject = this;
}
HttpResponseObserver.prototype = {
observe: function(aSubject, aTopic, aData){
if(aTopic=="http-on-examine-response"){
let httpChannel=aSubject.QueryInterface(Components.interfaces.nsIHttpChannel);
if(httpChannel.responseStatus== 555){
alert("555 Status code in Response ");
}
var newListener=new TracingListener();
aSubject.QueryInterface(Components.interfaces.nsITraceableChannel);
newListener.originalListener=aSubject.setNewListner(newListener);
}
}
QueryInterface: function(aIID)
{
if (!aIID.equals(nsISupports))
throw Components.results.NS_ERROR_NO_INTERFACE;
return this;
}
}
var HttpResponseObserverFactory = {
singleton: null,
createInstance: function (aOuter, aIID)
{
if (aOuter != null)
throw Components.results.NS_ERROR_NO_AGGREGATION;
if (this.singleton == null)
this.singleton = new HttpResponseObserver();
return this.singleton.QueryInterface(aIID);
}
};
var HttpResponseObserverModule = {
registerSelf: function(aCompMgr, aFileSpec, aLocation, aType)
{
aCompMgr = aCompMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
aCompMgr.registerFactoryLocation(CLASS_ID, CLASS_NAME, CONTRACT_ID, aFileSpec, aLocation, aType);
},
unregisterSelf: function(aCompMgr, aLocation, aType)
{
aCompMgr = aCompMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
aCompMgr.unregisterFactoryLocation(CLASS_ID, aLocation);
},
getClassObject: function(aCompMgr, aCID, aIID)
{
if (!aIID.equals(Components.interfaces.nsIFactory))
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
if (aCID.equals(CLASS_ID))
return HttpResponseObserverFactory;
throw Components.results.NS_ERROR_NO_INTERFACE;
},
canUnload: function(aCompMgr) { return true; }
};
function NSGetModule(aCompMgr, aFileSpec) { return HttpResponseObserverModule; }
//LISTENER
function TracingListener() {
this.originalListener = null;
}
TracingListener.prototype =
{
onDataAvailable: function(request, context, inputStream, offset, count) {
this.originalListener.onDataAvailable(request, context, inputStream, offset, count);
},
onStartRequest: function(request, context) {
this.originalListener.onStartRequest(request, context);
},
onStopRequest: function(request, context, statusCode) {
this.originalListener.onStopRequest(request, context, statusCode);
},
QueryInterface: function (aIID) {
if (aIID.equals(Components.interfaces.nsIStreamListener) ||
aIID.equals(Components.interfaces.nsISupports)) {
return this;
}
throw Components.results.NS_NOINTERFACE;
}
}
Thanks in advance. :D
that example is very complex, the main purpose of that traceable channel example is to get a COPY of the sourcecode that gets loaded at that uri.
const { interfaces: Ci, utils: Cu, classes: Cc, results: Cr } = Components;
Cu.import('resource://gre/modules/Services.jsm');
Cu.import('resource://gre/modules/devtools/Console.jsm');
var observers = {
'http-on-examine-response': {
observe: function (aSubject, aTopic, aData) {
console.info('http-on-examine-responset: aSubject = ' + aSubject + ' | aTopic = ' + aTopic + ' | aData = ' + aData);
var httpChannel = subject.QueryInterface(Ci.nsIHttpChannel);
if (httpChannel.responseStatus == 555) {
console.log('555 Status code in Response for request url = ' + httpChannel.URI.spec);
//httpChannel.cancel(Cr.NS_BINDING_ABORTED); //you might not need this, i think the redirectTo function handles aborting
httpChannel.redirectTo(Services.io.newURI('about:got bad response status so redirected you', null, null));
}
},
reg: function () {
Services.obs.addObserver(observers['http-on-examine-response'], 'http-on-modify-request', false);
},
unreg: function () {
Services.obs.removeObserver(observers['http-on-examine-response'], 'http-on-modify-request');
}
}
};
to register the observer on startup of addon run this:
//register all observers
for (var o in observers) {
observers[o].reg();
}
and on shutdown of addon unregister all observers like this:
//unregister all observers
for (var o in observers) {
observers[o].unreg();
}
Related
This question already has answers here:
chrome.runtime.onMessage response with async await
(7 answers)
Closed 1 year ago.
I am having an issue of asynchronicity (I believe). sendResponse() in contentscript.js does not wait for getThumbnails() to return.
I am sending a message in popup.js:
chrome.tabs.sendMessage(tabs[0].id, {message: "get_thumbnails", tabUrl: tabs[0].url},
function (respThumbnails) {
const thumbUrl = respThumbnails.payload;
console.log("payload", thumbUrl)
}
);
Then, in contentscript.js I listen for this message:
chrome.runtime.onMessage.addListener(async function(request,sender,sendResponse) {
if(request.message === "get_thumbnails") {
const payload = await getThumbnails();
console.log("thumbPayload after function:", payload)
sendResponse({payload:payload});
}
});
async function getThumbnails() {
let tUrl = null;
var potentialLocations = [
{sel: "meta[property='og:image:secure_url']", attr: "content" },
{sel: "meta[property='og:image']", attr: "content" },
];
for(s of potentialLocations) {
if(tUrl) return
const el = document.querySelector(s.sel);
if(el) {
tUrl = el.getAttribute(s.attr) || null;
}
}
return tUrl;
};
But it is also possible that the problem is coming from my getThumnails() function, because most of the times, payload is null and not undefined. So getThumbnails() might return before it is completely executed.
If this is the case, I have no idea why...
I also tried this code for getThubnails():
async function getThumbnails() {
let x = await function() {
let tUrl = null;
var potentialLocations = [
{sel: "meta[property='og:image:secure_url']", attr: "content" },
{sel: "meta[property='og:image']", attr: "content" },
];
for(s of potentialLocations) {
if(tUrl) return
const el = document.querySelector(s.sel);
if(el) {
tUrl = el.getAttribute(s.attr) || null;
}
}
return tUrl;
}
return x;
};
But this does not work, it seems to break my code...
The callback of onMessage should return a literal true value (documentation) in order to keep the internal messaging channel open so that sendResponse can work asynchronously.
Problem
Your callback is declared with async keyword, so it returns a Promise, not a literal true value. Chrome extensions API doesn't support Promise in the returned value of onMessage callback until https://crbug.com/1185241 is fixed so it's just ignored, the port is immediately closed, and the caller receives undefined in response.
Solutions
Remove the async keyword from before (request, sender, sendResponse), then...
Solution 1
Call an async function that can be embedded as an IIFE:
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.message === "get_thumbnails") {
(async () => {
const payload = await getThumbnails();
console.log("thumbPayload after function:", payload)
sendResponse({payload});
})();
return true; // keep the messaging channel open for sendResponse
}
});
Solution 2
Declare a separate async function and call it from the onMessage listener:
chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
if (msg.message === "get_thumbnails") {
processMessage(msg).then(sendResponse);
return true; // keep the messaging channel open for sendResponse
}
});
async function processMessage(msg) {
console.log('Processing message', msg);
// .................
return 'foo';
}
I am trying to implement Google Oauth2 consent screen within a popup but it says redirect URI mismatch. Is there any way where I can set up a web Ouath Client App without setting redirect uri in the dashboard?
I know setting up client type from web to others or application may solve this issue. But I want to implement it for web type only. Is this possible?
<!DOCTYPE html>
<html>
<head>
<script>
'use strict';
var GO2 = function GO2(options) {
if (!options || !options.clientId) {
throw 'You need to at least set the clientId';
}
if (typeof window != 'undefined'){
this._redirectUri = window.location.href.substr(0,
window.location.href.length -
window.location.hash.length)
.replace(/#$/, '');
}
// Save the client id
this._clientId = options.clientId;
// if scope is an array, convert it into a string.
if (options.scope) {
this._scope = Array.isArray(options.scope) ?
options.scope.join(' ') :
options.scope;
}
// rewrite redirect_uri
if (options.redirectUri) {
this._redirectUri = options.redirectUri;
}
// popup dimensions
if (options.popupHeight) {
this._popupHeight = options.popupHeight;
}
if (options.popupWidth) {
this._popupWidth = options.popupWidth;
}
if (options.responseType) {
this._responseType = options.responseType;
}
if (options.accessType) {
this._accessType = options.accessType;
}
};
GO2.receiveMessage = function GO2_receiveMessage() {
var go2;
if (window.opener && window.opener.__windowPendingGO2) {
go2 = window.opener.__windowPendingGO2;
}
if (window.parent && window.parent.__windowPendingGO2) {
go2 = window.parent.__windowPendingGO2;
}
var hash = window.location.hash;
if (go2 && hash.indexOf('access_token') !== -1) {
go2._handleMessage(
hash.replace(/^.*access_token=([^&]+).*$/, '$1'),
parseInt(hash.replace(/^.*expires_in=([^&]+).*$/, '$1'), 10),
hash.replace(/^.*state=go2_([^&]+).*$/, '$1')
);
}
if (go2 && window.location.search.indexOf('code=')) {
go2._handleMessage(
window.location.search.replace(/^.*code=([^&]+).*$/, '$1'),
null,
window.location.search.replace(/^.*state=go2_([^&]+).*$/, '$1')
);
}
if (go2 && window.location.search.indexOf('error=')) {
go2._handleMessage(false);
}
};
GO2.prototype = {
WINDOW_NAME: 'google_oauth2_login_popup',
OAUTH_URL: 'https://accounts.google.com/o/oauth2/v2/auth',
_clientId: undefined,
_scope: 'https://www.googleapis.com/auth/plus.me',
_redirectUri: '',
_popupWindow: null,
_immediateFrame: null,
_stateId: Math.random().toString(32).substr(2),
_accessToken: undefined,
_timer: undefined,
_popupWidth: 500,
_popupHeight: 400,
_responseType: 'token',
_accessType: 'online',
onlogin: null,
onlogout: null,
login: function go2_login(forceApprovalPrompt, immediate) {
if (this._accessToken) {
return;
}
this._removePendingWindows();
window.__windowPendingGO2 = this;
var url = this.OAUTH_URL +
'?response_type=' + this._responseType +
'&access_type='+ encodeURIComponent(this._accessType) +
'&redirect_uri=' + encodeURIComponent(this._redirectUri) +
'&scope=' + encodeURIComponent(this._scope) +
'&state=go2_' + this._stateId +
'&client_id=' + encodeURIComponent(this._clientId);
console.log(url);
if (!immediate && forceApprovalPrompt) {
url += '&approval_prompt=force';
}
if (immediate) {
url += '&approval_prompt=auto';
// Open up an iframe to login
// We might not be able to hear any of the callback
// because of X-Frame-Options.
var immediateFrame =
this._immediateFrame = document.createElement('iframe');
immediateFrame.src = url;
immediateFrame.hidden = true;
immediateFrame.width = immediateFrame.height = 1;
immediateFrame.name = this.WINDOW_NAME;
document.body.appendChild(immediateFrame);
return;
}
// Open the popup
var left =
window.screenX + (window.outerWidth / 2) - (this._popupWidth / 2);
var top =
window.screenY + (window.outerHeight / 2) - (this._popupHeight / 2);
var windowFeatures = 'width=' + this._popupWidth +
',height=' + this._popupHeight +
',top=' + top +
',left=' + left +
',location=no,toolbar=no,menubar=no';
this._popupWindow = window.open(url, this.WINDOW_NAME, windowFeatures);
},
logout: function go2_logout() {
if (!this._accessToken) {
return;
}
this._removePendingWindows();
clearTimeout(this._timer);
this._accessToken = undefined;
if (this.onlogout) {
this.onlogout();
}
},
getAccessToken: function go2_getAccessToken() {
return this._accessToken;
},
// receive token from popup / frame
_handleMessage: function go2_handleMessage(token, expiresIn, stateId) {
if (this._stateId !== stateId) {
return;
}
this._removePendingWindows();
// Do nothing if there is no token received.
if (!token) {
return;
}
this._accessToken = token;
if (this.onlogin) {
this.onlogin(this._accessToken);
}
if (expiresIn) {
// Remove the token if timed out.
clearTimeout(this._timer);
this._timer = setTimeout(
function tokenTimeout() {
this._accessToken = undefined;
if (this.onlogout) {
this.onlogout();
}
}.bind(this),
expiresIn * 1000
);
}
},
destory: function go2_destory() {
if (this._timer) {
clearTimeout(this._timer);
}
this._removePendingWindows();
},
_removePendingWindows: function go2_removePendingWindows() {
if (this._immediateFrame) {
document.body.removeChild(this._immediateFrame);
this._immediateFrame = null;
}
if (this._popupWindow) {
this._popupWindow.close();
this._popupWindow = null;
}
if (window.__windowPendingGO2 === this) {
delete window.__windowPendingGO2;
}
}
};
// if the context is the browser
if (typeof window !== 'undefined') {
// If the script loads in a popup matches the WINDOW_NAME,
// we need to handle the request instead.
if (window.name === GO2.prototype.WINDOW_NAME) {
GO2.receiveMessage();
}
}
// Expose the library as an AMD module
if (typeof define === 'function' && define.amd) {
define('google-oauth2-web-client', [], function () { return GO2; });
} else if (typeof module === 'object' && typeof require === 'function') {
// export GO2 in Node.js, assuming we are being browserify'd.
module.exports = GO2;
if (require.main === module) {
console.error('Error: GO2 is not meant to be executed directly.');
}
} else {
window.GO2 = GO2;
}
function test(){
var go2 = new GO2({
clientId: 'dfsdffdfgsfsdfggdgd.apps.googleusercontent.com',
redirectUri: 'http://localhost:8888/gapi/test.html',
responseType: 'code',
accessType: 'offline'
});
go2.login();
}
</script>
</head>
<body>
<a href='#' onClick='test();'> Click here to login </a>
</body>
</html>
It looks like you're using the implicit grant type which requires a redirect uri with response_type=token.
Can you use the authorization code grant type?
The redirect uri is optional for the authorization code grant type.
https://www.rfc-editor.org/rfc/rfc6749#section-4.1.1
I have a viewmodel which consists of a list(foreach loop) of DoctorPrices and when clicking on an item in the list it open up a CRUD form on the side. However when i update the values on the CRUD the observableArray that is bound to the foreach is not refreshing? (although the values are updates in the DB correctly)
From my data access module i call the following query.
function getDoctorServices(doctorId) {
var query = breeze.EntityQuery
.from('DoctorPrices')
.where('DoctorID', 'eq', doctorId).orderBy('ListOrder');
return manager.executeQueryLocally(query);
}
In my viewmodel i have the following code:
this.services = ko.computed(function() {
return doctorServices.getDoctorServices(doctorList.viewModel.instance.currentDoctorID());
});
services is bound using a foreach loop (not posting here as the code is simple and works)
When i click on a one of the DoctorPrices it gets the data as follows and places it in an observable:
this.selectedPrice = function (data, event) {
self.currentService(data);
self.showEdit(true);
};
I then bind selectPrice to a simple form that has the properties on it to be modified by the user. I then call manager.SaveChanges().
This results in the following problem: the value is being updated correctly but the GUI / Original List that is bound in the foreach is not being updated? Are the properties in breeze not observables? What is the best way to work with something like this.
I thought of a workaround and changing the code with something like this:
doctorList.viewModel.instance.currentDoctorID.subscribe(function() {
self.services([]);
self.services(doctorServices.getDoctorServices(doctorList.viewModel.instance.currentDoctorID()));
});
But i feel that clearing the array in that way is sloppy and not the right way of doing things specially with long lists.
Can someone please point me in the right direction on how to bind observableArray properties properly so they are updated?
Additional code my VM Component:
function services() {
var self = this;
this.showForm = ko.observable(false);
this.currentService = ko.observable();
this.services = ko.observableArray(doctorServices.getDoctorServices(doctorList.viewModel.instance.currentDoctorID()));
this.title = ko.observable();
doctorList.viewModel.instance.currentDoctorID.subscribe(function() {
self.services([]);
self.services(doctorServices.getDoctorServices(doctorList.viewModel.instance.currentDoctorID()));
self.showDetails(false);
});
this.show = function (value) {
self.showForm(value);
};
this.showDetails = ko.observable(false);
this.addNewService = function() {
self.currentService(doctorServices.createService(doctorList.viewModel.instance.currentDoctorID()));
console.log(self.currentService().entityAspect.entityState);
self.showDetails(true);
};
this.showDelete = ko.computed(function() {
if (self.currentService() == null)
return false;
else if (self.currentService().entityAspect.entityState.isDetached()) {
self.title('Add new service');
return false;
} else {
self.title('Edit service');
return true;
}
});
this.deleteService = function() {
self.currentService().entityAspect.setDeleted();
doctorServices.saveChanges();
doctorList.viewModel.instance.currentDoctorID.notifySubscribers();
};
this.closeDetails = function () {
doctorServices.manager.rejectChanges();
doctorList.viewModel.instance.currentDoctorID.notifySubscribers();
self.showDetails(false);
};
this.selectService = function (data, event) {
self.currentService(data);
self.showDetails(true);
};
this.saveChanges = function () {
console.log(self.currentService().entityAspect.entityState);
if (self.currentService().entityAspect.entityState.isDetached()) {
doctorServices.attachEntity(self.currentService());
}
console.log(self.currentService().entityAspect.entityState);
doctorServices.saveChanges();
doctorList.viewModel.instance.currentDoctorID.notifySubscribers();
self.currentService.notifySubscribers();
self.showDetails(true);
};
}
return {
viewModel: {
instance: new services()
},
template: servicesTemplate,
};
Below is my Breeze Data Class:
define('data/doctorServices', ['jquery', 'data/dataManager', 'knockout','mod/medappBase', 'breeze', 'breeze.savequeuing'], function ($, manager, ko,base, breeze, savequeuing) {
var services = ko.observableArray([]);
return {
attachEntity:attachEntity,
getServices: getServices,
services: services,
manager:manager,
getDoctorServices: getDoctorServices,
getServiceById: getServiceById,
createService:createService,
hasChanges: hasChanges,
saveChanges: saveChanges
};
function getServices() {
var query = breeze.EntityQuery.from("DoctorPrices");
return manager.executeQuery(query).then(function (data) {
services(data.results);
}).fail(function (data) {
console.log('fetch failed...');
console.log(data);
});;
}
function getDoctorServices(doctorId) {
var query = breeze.EntityQuery
.from('DoctorPrices')
.where('DoctorID', 'eq', doctorId).orderBy('ListOrder');
var set = manager.executeQueryLocally(query);
return set;
}
function getServiceById(serviceId) {
return manager.createEntity('DoctorPrice', serviceId);
//return manager.getEntityByKey('DoctorPrice', serviceId);
}
function handleSaveValidationError(error) {
var message = "Not saved due to validation error";
try { // fish out the first error
var firstErr = error.innerError.entityErrors[0];
message += ": " + firstErr.errorMessage;
base.addNotify('error', 'Could not save.', message);
} catch (e) { /* eat it for now */ }
return message;
}
function hasChanges() {
return manager.hasChanges();
}
function attachEntity(entity) {
manager.addEntity(entity);
}
function createService(doctorId) {
return manager.createEntity('DoctorPrice', { DoctorPricingID: breeze.core.getUuid(), DoctorID:doctorId }, breeze.EntityState.Detached);
};
function saveChanges() {
return manager.saveChanges()
.then(saveSucceeded)
.fail(saveFailed);
function saveSucceeded(saveResult) {
base.addNotify('success', 'Saved.', 'Your updates have been saved.');
}
function saveFailed(error) {
var reason = error.message;
var detail = error.detail;
if (error.innerError.entityErrors) {
reason = handleSaveValidationError(error);
} else if (detail && detail.ExceptionType &&
detail.ExceptionType.indexOf('OptimisticConcurrencyException') !== -1) {
// Concurrency error
reason =
"Another user, perhaps the server, " +
"may have deleted one or all of the settings." +
" You may have to restart the app.";
} else {
reason = "Failed to save changes: " + reason +
" You may have to restart the app.";
}
console.log(error);
console.log(reason);
}
}
});
Please note this is my frist attempt at both a data class and VM. At the moment i am relying heavily on clearing the array ([]) and using notifySubscribers to make the array refresh :(
I bet you're missing an observable somewhere. I can't tell because you keep hopping from property to property whose definition is not shown.
For example, I don't know how you defined this.currentService.
I'm confused by this:
this.services = ko.computed(function() {
return doctorServices.getDoctorServices(doctorList.viewModel.instance.currentDoctorID());
});
Why is it a ko.computed? Why not just make it an observable array.
self.service = ko.observableArray();
// ... later replace the inner array in one step ...
self.service(doctorServices.getDoctorServices(
doctorList.viewModel.instance.currentDoctorID()));
I urge you to follow the observability trail, confident that your Breeze entity properties are indeed observable.
vm.selectedPrice = ko.dependentObservable(function () {
return doctorServices.getDoctorServices(doctorList.viewModel.instance.currentDoctorID());
}, vm);
vm is ur model on which u applied bindings , try this it will work.
I want to be able to log in my Titanium app with credentials from my Rails app database.
In Titanium, I created the following model:
exports.definition = {
config: {
'adapter': {
'type': 'myAdapter',
'base_url': 'http://server:3000/api/users/'
}
},
extendModel: function(Model) {
_.extend(Model.prototype, {
// custom functions
login: function() {
this.sync("login", this);
}
});
return Model;
},
extendCollection: function(Collection) {
_.extend(Collection.prototype, {});
return Collection;
}
}
The sync adapter I created, from the Twitter example given in the official Appcelerator doc:
// Global URL variable
var BASE_URL = 'http://server:3000/api/';
// Override the Backbone.sync method with the following
module.exports.sync = function(method, model, options) {
var payload = model.toJSON();
var error;
switch(method) {
// custom cases
case 'login':
http_request('POST', BASE_URL + 'login', payload, callback);
break;
// This case is called by the Model.fetch and Collection.fetch methods to retrieve data.
case 'read':
// Use the idAttribute property in case the model ID is set to something else besides 'id'
if (payload[model.idAttribute]) {
// If we have an ID, fetch only one tweet
http_request('GET', BASE_URL + '', {
id : payload[model.idAttribute]
}, callback);
} else {
// if not, fetch as many as twitter will allow us
http_request('GET', BASE_URL + '', null, callback);
}
break;
// This case is called by the Model.save and Collection.create methods
// to a initialize model if the IDs are not set.
// For example, Model.save({text: 'Hola, Mundo'})
// or Collection.create({text: 'Hola, Mundo'}) executes this code.
case 'create':
if (payload.text) {
http_request('POST', BASE_URL + 'update.json', {
status : payload.text
}, callback);
} else {
error = 'ERROR: Cannot create tweet without a status!';
}
break;
// This case is called by the Model.destroy method to delete the model from storage.
case 'delete':
if (payload[model.idAttribute]) {
// Twitter uses a POST method to remove a tweet rather than the DELETE method.
http_request('POST', BASE_URL + 'destroy/' + payload[model.idAttribute] + '.json', null, callback);
} else {
error = 'ERROR: Model does not have an ID!';
}
break;
// This case is called by the Model.save and Collection.create methods
// to update a model if they have IDs set.
case 'update':
// Twitter does not have a call to change a tweet.
error = 'ERROR: Update method is not implemented!';
break;
default :
error = 'ERROR: Sync method not recognized!';
};
if (error) {
options.error(model, error, options);
Ti.API.error(error);
model.trigger('error');
}
// Simple default callback function for HTTP request operations.
function callback(success, response, error) {
res = JSON.parse(response);
console.log("response |" + response);
console.log("res |" + res);
console.log("res str |" + JSON.stringify(res))
console.log("options |" + options);
if (success) {
// Calls the default Backbone success callback
// and invokes a custom callback if options.success was defined.
options.success(res, JSON.stringify(res), options);
}
else {
// res.errors is an object returned by the Twitter server
var err = res.errors[0].message || error;
Ti.API.error('ERROR: ' + err);
// Calls the default Backbone error callback
// and invokes a custom callback if options.error was defined.
options.error(model, err, options);
model.trigger('error');
}
};
};
// Helper function for creating an HTTP request
function http_request(method, url, payload, callback) {
// Generates the OAuth header - code not included
var header;
//= generate_header(method, url, payload);
var client = Ti.Network.createHTTPClient({
onload : function(e) {
if (callback)
callback(true, this.responseText, null);
},
onerror : function(e) {
if (callback)
callback(false, this.responseText, e.error);
},
timeout : 5000
});
// Payload data needs to be included for the OAuth header generation,
// but for GET methods, the payload data is sent as a query string
// and needs to be appended to the base URL
if (method == 'GET' && payload) {
var values = [];
for (var key in payload) {
values.push(key + '=' + payload[key]);
}
url = url + '?' + values.join('&');
payload = null;
}
client.open(method, url);
//client.setRequestHeader('Authorization', header);
client.send(payload);
};
// Perform some actions before creating the Model class
module.exports.beforeModelCreate = function(config, name) {
config = config || {};
// If there is a base_url defined in the model file, use it
if (config.adapter.base_url) {
BASE_URL = config.adapter.base_url;
}
return config;
};
// Perform some actions after creating the Model class
module.exports.afterModelCreate = function(Model, name) {
// Nothing to do
};
The rails app responds with JSON and it works but the problem is in the callback function:
[INFO] : response |{"email":"huhu#gmail.com","password":null}
[ERROR] : Script Error {
[INFO] : res |[object Object]
[INFO] : res str |{"email":"huhu#gmail.com","password":null}
[INFO] : options |[object Object]
[ERROR] : backtrace = "#0 () at file://localhost/.../xxx.app/alloy/sync/myAdapter.js:4";
[ERROR] : line = 30;
[ERROR] : message = "'undefined' is not a function (evaluating 'options.success(res, JSON.stringify(res), options)')";
[ERROR] : name = TypeError;
[ERROR] : sourceId = 216868480;
[ERROR] : sourceURL = "file://localhost/.../xxx.app/alloy/sync/myAdapter.js";
[ERROR] : }
So, does somebody have an idea why options is undefined...? Note that if I call the fetch method to get users using the read method, it works. By the way, is there a good way in authenticating somebody?
you are not passing in an options parameter in your model try making a change like this below
this.sync("login", this, {
success: function() {},
error: function(){}
});
I've got this very strange error and I don't know how to deal with it.
My setup is a page in which I can select one image file, (gears beta.desktop) and then it should upload. But it doesn't upload, and gives a very strange error which I can't get away. below is my code:
var filesToUpload = null;
function progressEvent(event) {
var bar = $("#progressBar");
var percentage = Math.round((event.loaded / event.total) * 100);
bar.width(percentage + '%');
}
function uploadState() {
if(request.readyState == 4) {
if(request.status != 200) {
alert('ERROR');
} else {
alert('DONE');
}
}
}
function handleFiles(files) {
if(files.length) {
$('#loader').slideDown(500);
var curFile = files[0];
request.open('POST', 'upload.php');
request.setRequestHeader("Content-Disposition", "attachment; filename=\"" + curFile.name + "\"");
request.onreadystatechange = uploadState;
request.upload.onprogress = progressEvent;
request.send(curFile.blob);
}
}
init = function() {
if(!window.google || !google.gears) {
$('body').css('background', 'white');
$('#gearsOn').hide();
$('#gearsOff').show();
return;
}
// verberg 'geen gears' bericht
$('#gearsOff').hide();
// init upload zooi (gears)
desktop = google.gears.factory.create('beta.desktop');
request = google.gears.factory.create('beta.httprequest');
// on click funct
$('#titel').click(function() {
var newtitle = prompt("Voer een titel in voor het album.");
if(newtitle != '' && newtitle != null) {
$(this).text(newtitle);
}
});
$('.addPictures').click(function() {
filesToUpload = null;
var options = { singleFile: true, filter: [ 'image/jpeg', 'image/png'] };
desktop.openFiles(handleFiles, options);
});
};
$(document).ready(init);
It gives the following error:
[Exception... "Component returned failure code: 0x80004001 (NS_ERROR_NOT_IMPLEMENTED) [nsILoadGroup.groupObserver]" nsresult: "0x80004001 (NS_ERROR_NOT_IMPLEMENTED)" location: "JS frame :: file:///Users/Fabian/Library/Application%20Support/Firefox/Profiles/oo132cjy.default/extensions/%7Be3f6c2cc-d8db-498c-af6c-499fb211db97%7D/components/componentCollectorService.js :: anonymous :: line 1155" data: no]
[Break on this error] obj = getIface(request.loadGroup.groupObserver);
The thing is visible at this location: Dynamics Photo
Thanks in advance!!
I get this error when I'm using page speed - extension to firebug. If you use the same try to deactivate this extension.
disabling page speed did not helped... so uninstalled the extension.. and it works