Windows 8 App Development using Dhtmlxscheduler - javascript

I am writing a notification application which based on DHTMLxScheduler.
I would like to know more abut the idea of CRUD by IndexedDB for DHTMLxscheduler
As far I know, the following website shows an excellent example
http://www.codeproject.com/Articles/594924/Build-Calendar-App-for-Windows-8-with-dhtmlxSchedu
However, the data store is not persistent and the application would freeze during multi-touch event.
Does anyone can help to direct the coding needed for the CRUD by its default IndexedDB using the following?
scheduler.attachEvent("onEventDeleted",
function(event_id,event_object){
//add event to the data store
});
scheduler.attachEvent("onEventChanged", function(event_id, event_object){
//update event in the data store
});
scheduler.attachEvent("onEventAdded", function(event_id, event_object){
//delete event from the data store
});
The following example shows how to integrate by IndexedDB
http://www.dotnetcurry.com/ShowArticle.aspx?ID=868
However, they shares different framework, while the original scheduler sample used callback always to detect changes.
Thanks a lot for your help!

IndexedDB takes relatively lot of code for CRUD operation, so tutorial has been seriously simplified in order not to overload it with implementation details.
There is also complete example with working CRUD, check the '/samples/CalendarApp/' folder of this package:
http://dhtmlx.com/x/download/regular/dhtmlxScheduler_windows.zip
As for multi-touch issue, most probably it will be fixed in the nearest time. Current version of the package is based on dhtmlxScheduler3.7, we are going to update it to 4.0 which has an improvements for windows based touch devices.
And here is a example of database handling, similary to how it's done in the app from dhtmlx site.
//connect to indexedDb and fire the callback on success
function connect(callback){
try{
var db = null;
var req = window.indexedDB.open("SchedulerApp", 1);
req.onsuccess = function (ev) {
db = ev.target.result;
if(callback)//fire a callback on connect
callback(db);
}
req.onupgradeneeded = function(e){
//The event is fired when connecting to the new database, or on version change.
//This is the only place for defining database structure(object stores)
var db = ev.target.result;
if (!db.objectStoreNames.contains("events")) {
//create datastore, set 'id' as autoincremental key
var events = db.createObjectStore("events", { keyPath: "id", autoIncrement: true });
}
}
}catch(e){
}
}
//add js object to the database and fire callback on success
function insertEvent(data, callback) {
connect(function (db) {
var store = db.transaction("events", "readwrite").objectStore("events");
var updated = store.add(data);
updated.onsuccess = function (res) {
callback(res.target.result);
}
});
}
// use all defined above with the dhtmlxScheduler
// when user adds an event into the scheduler - it will be saved to the database
scheduler.attachEvent("onEventAdded", function (id) {
var ev = copyEvent(scheduler.getEvent(id));//where copyEvent is a helper function for deep copying
delete ev.id;//real id will be assigned by the database
insertEvent(ev, function (newId) {
scheduler.changeEventId(id, newId);//update event id in the app
});
return true;
});
However, I can't guarantee it will work right away, I can't test the code at the moment.
I'd also suggest you to check these articles on MSDN
FYI, I work for DHTMLX

Related

How do I check if an indexedDB instance is open?

Suppose I have an instance of an indexedDB object. Is there a simple way of detecting if the object is currently in the 'open' state?
I've tried database.closePending and looking at other properties but do not see a simple property that tells me the state of the database.
I am looking to do this synchronously.
Doing something like attempting open a transaction on a database and checking if an exception occurs is not a reasonable solution for me.
I don't want to maintain an extra variable associated with the database instance.
Perhaps I am missing some simple function in the api? Is there some observable feature of the instance variable that I can quickly and easily query to determine state?
Stated a different way, can you improve upon the following implementation?
function isOpen(db) {
if(db && Object.prototype.toString.call(db) === '[object IDBDatabase]') {
var names = db.objectStoreNames();
if(names && names.length) {
try {
var transaction = db.transaction(names[0]);
transaction.abort();
return true;
} catch(error) {
}
}
}
}
Or this method?
var opened = false;
var db;
var request = indexedDB.open(...);
request.onsuccess = function() {
db = request.result;
opened = true;
};
function isOpen(db) {
return opened;
}
db.close();
opened = false;
Or this method?
var db;
var request = indexedDB.open(...);
request.onsuccess = function() {
db = request.result;
db.onclose = function() {
db._secret_did_close = true;
};
};
function isOpen(db) {
return db instanceof IDBDatabase && !db.hasOwnProperty('_secret_did_close');
}
There's nothing else in the API that tells you if a connection is closed. Your enumeration of possibilities is what is available.
Also note that there is no closePending property in the API. The specification text uses a close pending flag to represent internal state, but this is not exposed to script.
Doing something like attempting open a transaction on a database and checking if an exception occurs is not a reasonable solution for me.
Why? This is the most reliable approach. Maintaining extra state would not account for unexpected closure (e.g. the user has deleted browsing data, forcing the connection to close) although that's what the onclose handler would account for - you'd need to combine your 2nd and 3rd approaches. (close is not fired if close() is called by script)
You should create a request by using indexedDB.open and if the connection is open you will jump onsuccess method.
request = indexedDB.open('html5',1);
request.onsuccess = function() {
console.log('Database connected');
};
Example :
https://codepen.io/headmax/pen/BmaOMR?editors=1111
About how to close or how to known if the indexedDB is still open : I guess you need to implement all events on every transaction : for example to take the control you can take the events : transaction.onerror, transaction.onabort ... If you need some example explanation i guess you have to create a new post ;).
https://developer.mozilla.org/en-US/docs/Web/API/IDBTransaction

PhoneGap Windows Phone 8 IndexedDB AbortError when opening db

Using essentially the example from the MDN IndexedDb tutorial I can see that my test IndexedDb code is working on Chrome. When I load the app onto my Windows Phone 8 device inside of the deviceready handler, I get an AbortError in the error handler for the database open request.
The only other related SO question was solved by fixing errors in onupgradeneeded but this handler is never even called in my code.
In this simple example, you have to run the fiddle twice because apparently onsuccess is called (where I read a test value) before onupgradeneeded (where I write the value when the db is initialized). I was going to deal with this once I got this first test to work.
http://jsfiddle.net/WDUVx/2/
// In the following line, you should include the prefixes of
// implementations you want to test.
window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
window.IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.msIDBTransaction;
window.IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange;
if (!window.indexedDB) {
window.alert("Your browser doesn't support a stable version of IndexedDB. Such and such feature will not be available.");
}
// open the database
var db;
var request = window.indexedDB.open("MyTestDatabase", 1);
request.onerror = function(e) {
alert("Couldn't open database: " + kc.util.getObjectString(e.target));
};
request.onsuccess = function(e) {
db = e.target.result;
var getRequest =
db.transaction("data")
.objectStore("data")
.get("firstObject")
.onsuccess = function(event) {
alert("Got: " + event.target.result.test);
};
};
request.onupgradeneeded = function(e) {
var db = event.target.result;
var objectStore = db.createObjectStore("data", {
autoincrement : false
});
objectStore.transaction.oncomplete = function(event) {
var myObjectStore = db.transaction("data", "readwrite").objectStore("data");
var addRequest = myObjectStore.add({
test : true
},
"firstObject");
addRequest.onerror = function(e) {
console.log("Error adding");
};
addRequest.onsuccess = function(e) {
console.log("Added!");
};
};
};
Questions:
What is my stupid mistake?
Are there any Windows Phone 8 examples of IndexedDb and PhoneGap? I could not find any after some searching. There were a few for an IndexedDb API Android and IOS polyfill, but none for wp8.
Is there something special that I have to do because I'm on a phone? Again, the code works in chrome.
Are there any other plugins that support wp8 storage > 5mb?
LocalStorage has a 5mb size limit
WebSQL is not supported
FileSystem plugin does not support filewriter.write(blob). This is what I am using for Android/iOS. It's strange that they say wp8 is supported by this plugin when this is the only way to actually write data, and you can't read the nothing you can write. I found that although the web api does not support it, the devices support filewriter.write(string). Windows Phone 8 is still not writing/reading things entirely correctly, but that is a separate question.
Recently, I faced a similar issue with indexed DB. My IndexedDB.open request was throwing an abort error.
After doing some search, I found suggestions to separate the requests for database creation and store creation.
Separating the code prevented the abort error. However, I noticed that the transaction to create the stores was sometimes run even before the completion of the database creation request.
This meant that my database connection was not closed from the first request, when the second request was run.
A minor fix was required to overcome this error. I moved the code to create stores to the success event for the first call.
Here is the code for reference.
function create_db(db_name)
{
var request = indexedDB.open(db_name);
request.onupgradeneeded=function(e)
{
console.log("1. creating database");
db=e.target.result;
};
request.onsuccess = function(e)
{
db = e.target.result;
console.log("1.1 database created successfully");
db.close();
add_tables(db_name);
};
request.onerror=function(e)
{
alert("error: "+ e.target.error.name + "failed creating db");
console.log("1.2 error creating db");
};
}
function add_tables(db_name)
{
var request = indexedDB.open(db_name,2);
request.onsuccess=function(e)
{
db=e.target.result;
console.log("2.2 table creation request successful");
};
request.onupgradeneeded=function(e)
{
db=e.target.result;
table = db.createObjectStore("table_name");
table.createIndex("id","id");
console.log("2.2 creating a single object store");
};
request.onerror=function(e)
{
console.log("2.3 error occured when creating tables");
};
};
Just some ideas, hope they help:
Don't use a global db variable. Do all of your work in callbacks. Using a global db variable can lead to numerous in-explainable situations, some of which include getting abort errors. Looking at your code, it actually looks like you are properly just using e.target, so I am not sure why you have a global var db.
Don't perform read/write requests on the version change transaction that occurs in the onupgradeneeded callback. Instead, perform requests when they are appropriate and let indexeddb worry about calling onupgradeneeded. In other words, don't retrieve the transaction in onupgradeneeded. Instead, just initiate some later transaction in a new connection as if the onupgradeneeded callback already completed.
openDBRequest having an abort event precedes onupgradeneeded callback
onupgradeneeded won't be called unless you make an attempt to connect to a database using a higher version
Listen for abort events. Add a callback to the open database request for onabort. Abort events sometimes occur because of things like opening two pages in the same context that try to access the same database. There could be something funky going on there.

Blockchain API, AJAX request has stopped working, CORS issues?

I've been playing with the multiple address look up API from blockchain info (documented here https://blockchain.info/api/blockchain_api), I had my code working earlier in the day but bizzarely it's stopped.
The purpose of it is to eventually write a little JQuery library which will search the DOM for bitcoin addresses as data attributes and then insert the final balance into that element creating a polling mechanism to keep the page updated as well.
The original problem I ran into earlier while developing it was because it's a CORS ajax request but later I adjusted the query per the blockchain info API documents and I added cors=true it then seemed to work fine but now it doesn't seem to want to work at all again. I don't get how changing computers would effect this kind of request.
Here's my code on JSFiddle, http://jsfiddle.net/SlyFoxy12/9mr7L/7/
My primary code is:
(function ($) {
var methods = {
init: function(data, options) {
//put your init logic here.
},
query_addresses: function(addresses) {
var addresses_implode = addresses.join("|");
$.getJSON("http://blockchain.info/multiaddr?cors=true&active="+addresses_implode, function( data ) {
$.each( data.addresses, function( index ) {
$('#output').append(" "+data.addresses[index].final_balance);
});
});
}
};
$.fn.bitstrap = function () {
var addresses = new Array();
$('[data-xbt-address]').each(function () {
$(this).text($(this).data('xbtAddress'));
addresses.push($(this).data('xbtAddress'));
});
methods.query_addresses(addresses);
}
}(jQuery));
$().ready(function() {
$().bitstrap();
});
Ok, turns out it's an issue with Chrome some how, I've tried it in safari and it works again, it must have been a different version of Chrome on the other computer I used.
There seems to be more info about it here https://code.google.com/p/chromium/issues/detail?id=104920

Error: The page has been destroyed and can no longer be used

I'm developing an add-on for the first time. It puts a little widget in the status bar that displays the number of unread Google Reader items. To accommodate this, the add-on process queries the Google Reader API every minute and passes the response to the widget. When I run cfx test I get this error:
Error: The page has been destroyed and can no longer be used.
I made sure to catch the widget's detach event and stop the refresh timer in response, but I'm still seeing the error. What am I doing wrong? Here's the relevant code:
// main.js - Main entry point
const tabs = require('tabs');
const widgets = require('widget');
const data = require('self').data;
const timers = require("timers");
const Request = require("request").Request;
function refreshUnreadCount() {
// Put in Google Reader API request
Request({
url: "https://www.google.com/reader/api/0/unread-count?output=json",
onComplete: function(response) {
// Ignore response if we encountered a 404 (e.g. user isn't logged in)
// or a different HTTP error.
// TODO: Can I make this work when third-party cookies are disabled?
if (response.status == 200) {
monitorWidget.postMessage(response.json);
} else {
monitorWidget.postMessage(null);
}
}
}).get();
}
var monitorWidget = widgets.Widget({
// Mandatory widget ID string
id: "greader-monitor",
// A required string description of the widget used for
// accessibility, title bars, and error reporting.
label: "GReader Monitor",
contentURL: data.url("widget.html"),
contentScriptFile: [data.url("jquery-1.7.2.min.js"), data.url("widget.js")],
onClick: function() {
// Open Google Reader when the widget is clicked.
tabs.open("https://www.google.com/reader/view/");
},
onAttach: function(worker) {
// If the widget's inner width changes, reflect that in the GUI
worker.port.on("widthReported", function(newWidth) {
worker.width = newWidth;
});
var refreshTimer = timers.setInterval(refreshUnreadCount, 60000);
// If the monitor widget is destroyed, make sure the timer gets cancelled.
worker.on("detach", function() {
timers.clearInterval(refreshTimer);
});
refreshUnreadCount();
}
});
// widget.js - Status bar widget script
// Every so often, we'll receive the updated item feed. It's our job
// to parse it.
self.on("message", function(json) {
if (json == null) {
$("span#counter").attr("class", "");
$("span#counter").text("N/A");
} else {
var newTotal = 0;
for (var item in json.unreadcounts) {
newTotal += json.unreadcounts[item].count;
}
// Since the cumulative reading list count is a separate part of the
// unread count info, we have to divide the total by 2.
newTotal /= 2;
$("span#counter").text(newTotal);
// Update style
if (newTotal > 0)
$("span#counter").attr("class", "newitems");
else
$("span#counter").attr("class", "");
}
// Reports the current width of the widget
self.port.emit("widthReported", $("div#widget").width());
});
Edit: I've uploaded the project in its entirety to this GitHub repository.
I think if you use the method monitorWidget.port.emit("widthReported", response.json); you can fire the event. It the second way to communicate with the content script and the add-on script.
Reference for the port communication
Reference for the communication with postMessage
I guess that this message comes up when you call monitorWidget.postMessage() in refreshUnreadCount(). The obvious cause for it would be: while you make sure to call refreshUnreadCount() only when the worker is still active, this function will do an asynchronous request which might take a while. So by the time this request completes the worker might be destroyed already.
One solution would be to pass the worker as a parameter to refreshUnreadCount(). It could then add its own detach listener (remove it when the request is done) and ignore the response if the worker was detached while the request was performed.
function refreshUnreadCount(worker) {
var detached = false;
function onDetach()
{
detached = true;
}
worker.on("detach", onDetach);
Request({
...
onComplete: function(response) {
worker.removeListener("detach", onDetach);
if (detached)
return; // Nothing to update with out data
...
}
}).get();
}
Then again, using try..catch to detect this situation and suppress the error would probably be simpler - but not exactly a clean solution.
I've just seen your message on irc, thanks for reporting your issues.
You are facing some internal bug in the SDK. I've opened a bug about that here.
You should definitely keep the first version of your code, where you send messages to the widget, i.e. widget.postMessage (instead of worker.postMessage). Then we will have to fix the bug I linked to in order to just make your code work!!
Then I suggest you to move the setInterval to the toplevel, otherwise you will fire multiple interval and request, one per window. This attach event is fired for each new firefox window.

Background tasks in JavaScript that do not interfere UI interaction

I am working on a mobile App implemented in JavaScript that has to do lots of background stuff -- mainly fetching data from a server (via JSONP) and writing it into a database using local storage. In the foreground the user may navigate on the locally stored data and thus wants a smoothly reacting App.
This interaction (fetching data from server via JSONP and after doing some minor work with it, storing it in the local database) is done asynchronously, but because of the necessary DOM manipulation for JSONP and the database interaction I am not able to this work with WebWorkers. Thus I am running in the problem in blocking the JavaScript event queue with lots of "background processing requests" and the App reacts very slowly (or even locks completely).
Here is a small sketch of the way I am doing the background stuff:
var pendingTasksOnNewObjects = new Object();
//add callbacks to queue
function addTaskToQueue(id, callback) {
if (!pendingTasksOnNewObjects[id]) {
pendingTasksOnNewObjects[id] = new Array();
}
pendingTasksOnNewObjects[id].push(callback);
}
// example for this pending tasks:
var myExampleTask = function () {
this.run = function(jsonObject) {
// do intersting stuff here as early as a specific new object arrives
// i.e. update some elements in the DOM to respect the newly arrived object
};
};
addTaskToQueue("id12345", myExampleTask);
// method to fetch documents from the server via JSONP
function getDocuments(idsAsCommaSeparatedString) {
var elem;
elem = document.createElement("script");
elem.setAttribute("type", "text/javascript");
elem.setAttribute("src", "http://serverurl/servlet/myServlet/documents/"+idsAsCommaSeparatedString);
document.head.appendChild(elem);
}
// "callback" method that is used in the JSONP result to process the data
function locallyStoreDocuments(jsonArray) {
var i;
for (i=0; i<jsonArray.length; i++) {
var obj = jsonArray[i];
storeObjectInDatabase(obj);
runTasks(obj.docID, obj);
}
return true;
}
// process tasks when new object arrives
function runTasks(id, jsonObject) {
if(pendingTasksOnNewObjects[id]) {
while(pendingTasksOnNewObjects[id][0]) {
pendingTasksOnNewObjects[id][0].run(jsonObject);
pendingTasksOnNewObjects[id].shift();
}
}
return true;
}
I already looked around reading some stuff about the event processing mechanisms in JavaScript (i.e. John Resigs description of working with timers), but what I really want to do is the following: Check if there is something to do in the event queue. If so, wait for 100ms and check again. If nothing is currently waiting in the queue, process a small amount of data and check again.
As far as I read, this is not possible, since JavaScript does not have direct access to the event queue.
So are there any design ideas on how to optimize my code to get closer to the goal not to interfere with the UI events to give the user a smooth App interaction?
Web Workers seem to be available in iOS 5, http://caniuse.com/webworkers

Categories

Resources