I'm trying to create a bookmark extension in Chrome and I want to leverage WebSQL to store all kind of information about bookmarks locally. Here's what I've done so far:
(function() {
var Home,
__bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
window.requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem;
Home = (function() {
function Home() {
this.onDBInit = __bind(this.onDBInit, this); this.db = openDatabase("Journal", "", "Bookmarks Stats", 5 * 1024 * 1024, this.onDBInit, this.onDBError);
}
Home.prototype.onDBInit = function(db) {
console.log(db.version);
db.changeVersion("", "1.0", this.initDB, this.onDBError);
return console.log(db);
};
Home.prototype.initDB = function(t) {
console.log(t);
return t.executeSql('CREATE TABLE bookmarks (id, title, url)');
};
Home.prototype.onDBError = function(e) {
return console.log(e);
};
return Home;
})();
window.Registerable(Home);
}).call(this);
For some reason, changeVersion ALWAYS fails. I have tried to delete the database, restart chrome, etc. Chrome version: 18.
In my limited experience, changeVersion does work on Chrome. I've also read complaints here about it not working properly on Safari, but it does.
However, there are two catches:
Catch 1:
Often, changeVersion appears to fail (it gives an error and db.version will still return the old value), but the transaction callback will fire and when you re-open the web page and its database, the version number will be correct.
Catch 2:
It seems you must supply precisely five arguments, including three callbacks. If you don't supply these five arguments, for example you only do the first three, then the current version will remain unchanged. So if you were to follow the instruction in this tutorial that everyone's referring to, you would be disappointed.
This is the case for Chrome and Safari on Windows.
Arguments are:
1: expected version
2: new version
3: transaction callback (you can execute SQL here as part of the version change)
4: failure callback (if version change or transaction callback failed)
5: succes callback (if version change and transaction callback succeeded)
I haven’t tested this on iOS devices but it matches the Safari specifications provided here:
https://developer.apple.com/library/safari/#documentation/iphone/conceptual/safarijsdatabaseguide/usingthejavascriptdatabase/usingthejavascriptdatabase.html
In Opera, changeVersion waits with setting db.version to its new value until after you've executed an actual sql transaction using executeSql. So I use a SELECT statement that has no further consequence. This does not actually have to be inside the transaction callback: I discovered it when I tried a separate executeSql statement in the browser console after trying a whole bunch of changeVersion commands.
This is Chrome bug: you can not change the version of the database with an empty string in the value.
And according to the specifications in the call creationCallback (in your case, the function onDBInit) version of the database is exposed to an empty string:
the callback is invoked with the database having the empty string as its version regardless of the given database version
This error is detected two years ago and described in detail, but is still not corrected
I have decided this issue in the following ways: I removed the initialization of the database structure of creationCallback and made it the first transaction to the database.
var db = openDatabase("Journal", "0.1", "Bookmarks Stats", 5 * 1024 * 1024);
db.transaction(function (t) {
t.executeSql('CREATE TABLE IF NOT EXISTS bookmarks (id, title, url)');
});
Related
I use Meteor Dev Tools plugin in Chrome, and I’ve noticed a cool new feature, that is worrying me about the way I've coded my app.
The audit collection tool is telling me that some of my collections are insecure.
I am still using Meteor 1.2 with Blaze
1.
One of them is meteor_autoupdate_clientVersions
1.1. should I worry about this one?
1.2. How do I protect it?
Insert, Update and Remove are marked as insecure.
2.
Then I have a cycles collection, which has marked as insecure: update and remove
This collection is updated on the database now and then but not supposed to be accessed from the frontend, and is not meant to be related to any client interaction.
For this collection I have these allow/deny rules in a common folder (both client and server)
I've tried applying these rules only on the server side, but I didn't see a difference on the audit results.
2.1. Should these rules be only on the server side?
Cycles.allow({
insert: function () {
return false;
},
remove: function () {
return false;
},
update: function () {
return false;
}
});
Cycles.deny({
insert: function () {
return true;
},
remove: function () {
return true;
},
update: function () {
return true;
}
});
2.2. How do I protect this collection?
3.
And then, I also have another collection with an insecure check which is users, where remove is marked as insecure.
On this webapp I don't make any use of users, there is no login, etc.
I might want to implement this in the future, though.
3.1 Should I worry about this collection being insecure, since I don't use it at all?
3.2 How do I protect this collection?
You do not have to allow or deny. Just remove the insecure package from the meteor app.
Then you can use publish/subscribe and methods for data insert, update and delete.
Remove this please fo code from app:
Cycles.allow({
insert: function () {
return false;
},
remove: function () {
return false;
},
update: function () {
return false;
}
});
Cycles.deny({
insert: function () {
return true;
},
remove: function () {
return true;
},
update: function () {
return true;
}
});
For 1.1
This happens while the user is logging.
Basically, issue is not with this but with the login method.
see wait time: https://ui.kadira.io/pt/2fbbd026-6302-4a12-add4-355c0480f81d
why login method slow?
This happens when everytime, your app gets reconnected. So, after the sucessful login, it will re-run all the publications again. That's why you saw such a delay to login hence this publication.
There is no such remedy for this and but this is kind fine unless your app is having a lot of througput/subRate to this method/publication.
For 3.1 :
You do not have to worry about inscure anymore after removing allow/deny and insecure package. But make sure, you write secure methods.
I have a WebGL app using three.js. It has been running fine for months until today, September 7th, 2014.
It no longer runs on Chrome, however, it still continues to run on Firefox and Safari.
I have traced the problem to a specific condition.
I load objects from json files like this:
loader.load("assets/Tables.json", callback_mesh, "assets/maps/", parent.texturesTable);
The callback_mesh function looks like this:
var callback_mesh = function (result, materials, userData) {
for (var i = 0; i < materials.length; i++) {
if (materials[i].uniforms != undefined) {
materials[i].uniforms.tDiffuse.value = userData[TEXTURE_DIFFUSE];
materials[i].uniforms.tNormal.value = userData[TEXTURE_NORMAL];
materials[i].uniforms.tSpecular.value = userData[TEXTURE_SPECULAR];
}
}
var mesh = new THREE.Mesh(result, new THREE.MeshFaceMaterial(materials));
mesh.scale.set(1, 1, 1);
mesh.receiveShadow = true;
mesh.castShadow = true;
objects.push(mesh);
}
The above code no longer runs in Chrome.
If I remove the line "mesh.receiveShadow = true", it works fine.
If I create a new material, instead of using the materials from the json file and modifying their parameters/uniforms, I can leave the receiveShadow set to true and it works.
So the rather specific issue is when I import an object from a json file and assign the materials array that comes from the json file to the mesh as a MeshFaceMaterial and turn on receiveShadow, the object does not load and I get the following error message:
THREE.WebGLProgram: gl.getProgramInfoLog() (260,64-140): warning X3550: sampler array index must be a literal expression, forcing loop to unroll
(89,12): error X6077: texld/texldb/texldp/dsx/dsy instructions with r# as source cannot be used inside dynamic conditional 'if' blocks, dynamic conditional subroutine calls, or loop/rep with break*.
Failed to create D3D shaders.
three.js:25545
59WebGL: INVALID_OPERATION: getUniformLocation: program not linked three.js:25283
21WebGL: INVALID_OPERATION: getAttribLocation: program not linked
And, again, I never saw this prior to today, maybe there was a Chrome update. And it works fine under Firefox and Safari, the mesh loads with receiveShadows on and the shadows are rendered.
In the current Chrome, it works only if I turn off receiveShadows.
Anyone have this same problem or have any thoughts on what might be causing this?
Thanks.
-mat
This issue has been bugging me since the inception of the new Google Drive Android Api (GDAA).
First discussed here, I hoped it would go away in later releases, but it is still there (as of 2014/03/19). The user-trashed (referring to the 'Remove' action in 'drive.google.com') files/folders keep appearing in both the
Drive.DriveApi.query(_gac, query), and
DriveFolder.queryChildren(_gac, query)
as well as
DriveFolder.listChildren(_gac)
methods, even if used with
Filters.eq(SearchableField.TRASHED, false)
query qualifier, or if I use a filtering construct on the results
for (Metadata md : result.getMetadataBuffer()) {
if ((md == null) || (!md.isDataValid()) || md.isTrashed()) continue;
dMDs.add(new DrvMD(md));
}
Using
Drive.DriveApi.requestSync(_gac);
has no impact. And the time elapsed since the removal varies wildly, my last case was over 12 HOURS. And it is completely random.
What's worse, I can't even rely on EMPTY TRASH in 'drive.google.com', it does not yield any predictable results. Sometime the file status changes to 'isTrashed()' sometimes it disappears from the result list.
As I kept fiddling with this issue, I ended up with the following superawfulhack:
find file with TRASH status equal FALSE
if (file found and is not trashed) {
try to write content
if ( write content fails)
create a new file
}
Not even this helps. The file shows up as healthy even if the file is in the trash (and it's status was double-filtered by query and by metadata test). It can even be happily written into and when inspected in the trash, it is modified.
The conclusion here is that a fix should get higher priority, since it renders multi-platform use of Drive unreliable. It will be discovered by developers right away in the development / debugging process, steering them away.
While waiting for any acknowledgement from the support team, I devised a HACK that allows a workaround for this problem. Using the same principle as in SO 22295903, the logic involves falling back to RESTful API. Basically, dropping the LIST / QUERY functionality of GDAA.
The high level logic is:
query the RESTful API to retrieve the ID/IDs of file(s) in question
use retrieved ID to get GDAA's DriveId via 'fetchDriveId()'
here are the code snippets to document the process:
1/ initialize both GDAA's 'GoogleApiClient' and RESTful's 'services.drive.Drive'
GoogleApiClient _gac;
com.google.api.services.drive.Drive _drvSvc;
void init(Context ctx, String email){
// build GDAA GoogleApiClient
_gac = new GoogleApiClient.Builder(ctx).addApi(com.google.android.gms.drive.Drive.API)
.addScope(com.google.android.gms.drive.Drive.SCOPE_FILE).setAccountName(email)
.addConnectionCallbacks(ctx).addOnConnectionFailedListener(ctx).build();
// build RESTFul (DriveSDKv2) service to fall back to
GoogleAccountCredential crd = GoogleAccountCredential
.usingOAuth2(ctx, Arrays.asList(com.google.api.services.drive.DriveScopes.DRIVE_FILE));
crd.setSelectedAccountName(email);
_drvSvc = new com.google.api.services.drive.Drive.Builder(
AndroidHttp.newCompatibleTransport(), new GsonFactory(), crd).build();
}
2/ method that queries the Drive RESTful API, returning GDAA's DriveId to be used by the app.
String qry = "title = 'MYFILE' and mimeType = 'text/plain' and trashed = false";
DriveId findObject(String qry) throws Exception {
DriveId dId = null;
try {
final FileList gLst = _drvSvc.files().list().setQ(query).setFields("items(id)").execute();
if (gLst.getItems().size() == 1) {
String sId = gLst.getItems().get(0).getId();
dId = Drive.DriveApi.fetchDriveId(_gac, sId).await().getDriveId();
} else if (gLst.getItems().size() > 1)
throw new Exception("more then one folder/file found");
} catch (Exception e) {}
return dId;
}
The findObject() method above (again I'm using the 'await()' flavor for simplicity) returns the the Drive objects correctly, reflecting the trashed status with no noticeable delay (implement in non-UI thread).
Again, I would strongly advice AGAINST leaving this in code longer than necassary since it is a HACK with unpredictable effect on the rest of the system.
I was trying to understand how to use the chrome.storage.api.
I have included the following in my manifest.json:
"permissions": [
"activeTab","storage"
],
Than, I opened a new tab with the devtools and switched the <page context> to the one of my chrome-extension. Than I typed:
chrome.storage.sync.set({"foo":"bar"},function(){ console.log("saved ok"); } );
and got:
undefined
saved ok
Than I tried getting this stored value:
chrome.storage.sync.get("foo",function(data){ console.log(data); } );
but this got me:
undefined
Object {}
Than I did the same, but instead of sync I used local and this worked as expected:
chrome.storage.local.set({"foo":"bar"},function(){ console.log("saved ok"); } );
..and the retrieval:
chrome.storage.local.get("foo",function(data){ console.log(data); } );
Which got me: Object {foo: "bar"} as it should.
Is this because I am not signed in to my account on chrome? But in that case, isn't chrome.storage.sync designed to fallback into storing the data locally?
EDIT
Strangely, when i type this straight on console it seems to be working, but this code doesn't run from background.js code inside a click listener:
var dataCache = {};
function addStarredPost(post)
{
var id = getPostId(post);
var timeStamp = new Date().getTime();
var user = getUserName();
dataCache[id] = {"id":id,"post":post,"time":timeStamp,"user":user};
chrome.storage.sync.set(dataCache,function(){ console.log("Starred!");});
}
After this is ran, chrome.storage.sync.get(null,function(data){ console.log(data); }); returns an empty object as if the data wasn't stored. :/
This code seems to be working perfect with chrome.storage.local instead.
chrome.runtime.lastErros returns undefined
The max size for chrome local storage is 5,242,880 bytes.
To extend the storage you can add on the manifest.json :
"permissions": [
"unlimitedStorage"
]
The max size for chrome sync storage is:
102,400 bytes total
8,192 bytes per item
512 items max
1,800 write operations per hour
120 operations per minutes
(source)
Whoops!
The problem was I was trying to sync data that exceeded in size. (4096 Bytes per item)
I wasn't getting chrome.runtime.lastError because I was mistakenly putting it inside the get function scope, instead of the set function which was producing the error. Hence, I'm posting this answer so it might help others who share the same confusion.
You should check chrome.runtime.lastError inside each api call, like so:
chrome.storage.local.set(objectToStore, function(data)
{
if(chrome.runtime.lastError)
{
/* error */
console.log(chrome.runtime.lastError.message);
return;
}
//all good. do your thing..
}
This ran OK with chrome.storage.local because according to the docs you only have this limitation with sync.
printing chrome.runtime.lastError gave me: Object {message: "QUOTA_BYTES_PER_ITEM quota exceeded"}
First of all, I'm using the most recent of Rx, that is 2.1. As far as I understand, lots of things have changed when Rx turned 2, so I'm really looking forward to receive an up-to-date answer. Thanks in advance.
I'm implementing a classic task for Rx: observing text of TextBox (AutoCompleteBox from WPToolkit to be exact), in order to provide a list of suggestions to user. Suggestions are fetched from the network, and I want to use these ordinary Rx goodies, like Throttle, DistinctUntilChanged, etc.
I'm also using recently released portable HttpClient for Windows Phone 8, since it provides task-based asynchronous API, which is nice.
The problem I'm having is the cross-thread access while reading the Text value of 'AutoCompleteBox`. Here is the code:
var http = new HttpClient();
var searchFunc = Observable.FromAsync<HttpResponseMessage>(() =>
http.GetAsync(FormatUrl(SEARCH_URL, "DE", new GeoCoordinate(51, 13), searchBox.Text /* <-- causes exception */, 10, "")));
var uithread = new SynchronizationContextScheduler(SynchronizationContext.Current);
var textChange = Observable.FromEventPattern<RoutedEventArgs>(searchBox, "TextChanged")
.Throttle(TimeSpan.FromMilliseconds(800))
.DistinctUntilChanged()
.SubscribeOn(uithread)
.SelectMany(searchFunc)
.Select(async (resp) => SearchResultsParser.ParseSearchResults(await resp.Content.ReadAsStreamAsync(), new GeoCoordinate(51, 13)))
.Select(async (results) => searchBox.ItemsSource = await results)
.ObserveOn(uithread)
.Subscribe();
Exception happens when searchFunc is executed. I see from VS that it executes on a Worker Thread, despite I use SubscribeOn.
Here's the example using SynchronizationContextScheduler, but I've also tried just SubscribeOnDispatcher, with the same result. Looks like I'm missing something important with this ObserveOn stuff, or maybe regarding Observable.FromAsync. Could you kindly point me to my mistake?
SubscribeOn is almost never what you want - you might think it means "Where my Subscribe method runs", but it actually means "Where the actual wiring to the IDisposable (and disposal) runs" - ObserveOn is the equivalent for "This is where I want my actual Subscribe code to execute"
Ref: Observable.SubscribeOn and Observable.ObserveOn