MozillaZine

Places (bookmarks & history system) - API changes

Talk about add-ons and extension development.
Ken Saunders

User avatar
 
Posts: 1007
Joined: March 14th, 2005, 2:52 pm
Location: Mozillaopolis

Post Posted January 27th, 2013, 4:16 am

Hi All,
I Just wanted to repost something that I came across that might affect some of you.

Ken


Heads up: add-ons using Places (bookmarks & history system) - API changes!
http://groups.google.com/group/mozilla. ... 8c19eb027#


Marco Bonardo
Jan 24, 5:17 pm
(Please followup-to mozilla.dev.extensions)

Dear add-ons developers,
as part of our goal to make history and bookmarks asynchronous, we are
starting removing some APIs, that in the last years have been replaced
by new asynchronous ones.
We are currently removing the last uses in the tests harness, but we are
not too far from the target. Current goal is Firefox21.

The work is tracked in https://bugzilla.mozilla.org/show_bug.cgi?id=834457

The following APIs will be removed:

(replaced by mozIAsyncFavicons)
nsIFaviconService::setFaviconUrlForPage
nsIFaviconService::setFaviconData
nsIFaviconService::getFaviconData
nsIFaviconService::getFaviconForPage
nsIFaviconService::setAndLoadFaviconForPage
nsIFaviconService::getFaviconImageForPage
nsIFaviconService::getFaviconDataAsDataURL

(replaced by mozIAsyncLivemarks)
nsILivemarkService::*
PlacesUtils.itemIsLivemark
PlacesUtils.nodeIsLivemarkContainer
PlacesUtils.nodeIsLivemarkItem

(remove only third argument)
PlacesUIUtils.showBookmarkDialog

(no more implemented by Places, use mozIAsyncHistory)
nsIGlobalHistory2::addURI
nsIGlobalHistory2::isVisited
nsIGlobalHistory2::setPageTitle

In addition to this, if current issues will be solved soon, the
following will also be removed:

nsINavHistoryObserver::OnBeforeDeleteURI
nsINavBookmarkObserver::OnBeforeItemRemoved

Please let me know if you have doubts, or part of these changes should
be blocked for major problems, or there's some use-case you need that is
not well-covered by the new APIs.

Cheers,
Marco

DAC324
 
Posts: 144
Joined: October 19th, 2007, 1:54 am

Post Posted September 19th, 2013, 3:17 am

Dear Ken, dear all,

thank you very much for that information. Please allow me one question:

If I happen to have all required parameters, such as title, parentId, index and feedURI, available as single variables, how do I get them into a mozILivemarkInfo object as required now by addLivemark()?

Update: Seems that it should be something like
Code: Select all
PlacesUtils.livemarks.addLivemark ({
                                                            parentId: aParentId,
                                                            index: aIndex, 
                                                            feedURI: aFeedURI,
                                                            siteURI: aSiteURI,
                                                            title: aName,
                                                             });


But: The older functions like PlacesUtils.livemarks.createLivemarkFolderOnly used to return an Id while PlacesUtils.livemarks.addLivemark is void (does not return anything).

What about that Id? Gen I get it somewhere else?

Thank you very much in advance and kind regards,

DAC324

lithopsian
 
Posts: 3344
Joined: September 15th, 2010, 9:03 am

Post Posted September 19th, 2013, 8:09 am

Places API is now async. addLivemark accepts a callback which will be given the ID when it is available, pretty much instantly as far as you are concerned but actually after a millisecond or two without blocking the main thread.

The callback is the second parameter, after the object you show, and it is a function that will be called with a status code and a livemark object. The livemark object has an id property.

There was no documentation when this change qwas made to the API and I don't think there is any now. The interface is called mozIAsyncLivemarks and you can see the definition here:
http://mxr.mozilla.org/mozilla-central/ ... rks.idl#31

DAC324
 
Posts: 144
Joined: October 19th, 2007, 1:54 am

Post Posted September 20th, 2013, 9:06 am

Dear lithopsian,
lithopsian wrote:Places API is now async. addLivemark accepts a callback which will be given the ID when it is available, pretty much instantly as far as you are concerned but actually after a millisecond or two without blocking the main thread.

The callback is the second parameter, after the object you show, and it is a function that will be called with a status code and a livemark object. The livemark object has an id property.

Thank you very much for this information, which is consistent with what I already found out by myself. Unfortunately, it seems that I am missing something important, however.

I have defined a function which should be called as a callback function. This function simply should log the information it got into a logfile:
Code: Select all
        function completed (aStatus, aLivemark){
            MyProgIO.log ("Status: " + aStatus + "Id: " + aLivemark.id);
        };

In order to be on the safe side, I call addlivemarks() using a try...catch construction:
Code: Select all
        try {
            PlacesUtils.livemarks.addLivemark ({
                                                            parentId: aParentId,
                                                            index: aIndex, 
                                                            feedURI: aFeedURI,
                                                            siteURI: aSiteURI,
                                                            title: aName
                                                             }, completed);
                                                             
            }
            catch(e) {
                    MyProgIO.log("Failed to add livemark " + aName + ": " + e + e.message);
            }                                                 

Unfortunately, the function completed() does not seem to either get called or to do anything. The expected "Status:..." entry does not appear in the logfile.

Kind regards,

DAC324
Last edited by DAC324 on September 20th, 2013, 4:26 pm, edited 1 time in total.

lithopsian
 
Posts: 3344
Joined: September 15th, 2010, 9:03 am

Post Posted September 20th, 2013, 11:30 am

Slight clarification: the mozILivemarkCallback is an OBJECT, which has a single property onCompletion, which is a function accepting two parameters.

DAC324
 
Posts: 144
Joined: October 19th, 2007, 1:54 am

Post Posted September 20th, 2013, 4:20 pm

Hello lithopsian,

thank you once again. But how can I access this callback object properly?
I just want to get the ID of the newly created livemark.

Seems that I now solved it:
Code: Select all
  createLivemarkFolderOnly: function(aParentId, aName, aSiteURI, aFeedURI, aIndex) {

        var completed = this;
       
        completed.onCompletion = function (aStatus, aLivemark){
              MyProgIO.log("Livemark Id: " + aLivemark.id);
              receivedIds.push(aLivemark.id);
        };

        if (aParentId < 1 || !aFeedURI)
          throw Cr.NS_ERROR_INVALID_ARG;

        // Don't add livemarks to livemarks
        if (PlacesUtils.annotations.itemHasAnnotation(aParentId, SyncPlacesBookmarks.SP_LMANNO_FEEDURI))
          throw Cr.NS_ERROR_INVALID_ARG;
        try {
            PlacesUtils.livemarks.addLivemark ({
                                                            parentId: aParentId,
                                                            index: aIndex, 
                                                            feedURI: aFeedURI,
                                                            siteURI: aSiteURI,
                                                            title: aName,
                                                             }, completed);
            }
            catch(e) {
                    MyProgIO.log("Failed to add livemark " + aName + ": " + e + e.message);
            }                                                 
  }


Kind regards,

DAC324
Last edited by DAC324 on September 26th, 2013, 7:01 am, edited 1 time in total.

DAC324
 
Posts: 144
Joined: October 19th, 2007, 1:54 am

Post Posted September 26th, 2013, 3:32 am

Hello all,

one interesting thing is that PlacesUtils.livemarks.addLivemark() is not fully finished when my function createLivemarkFolderOnly() returns. The callback component executes later on only.
Here is how the log looks like:
Thursday, 26. September 2013 14:13:50 Trying to add livemark heise online News, http://heise.de.feedsportal.com/c/35207 ... /index.rss, http://heise.de.feedsportal.com/c/35207 ... /index.rss, 10
Thursday, 26. September 2013 14:13:50 Livemark Folder Id: 0
Thursday, 26. September 2013 14:13:52 Trying to add livemark Caschys Blog, http://stadt-bremerhaven.de/, http://feeds.feedburner.com/stadt-breme ... format=xml, 11
Thursday, 26. September 2013 14:13:52 Livemark Folder Id: 0
[...]
Thursday, 26. September 2013 14:13:52 Livemark Id from callback: 1515
Thursday, 26. September 2013 14:13:52 Livemark Id from callback: 1516


Now I added the handling of the ID given back into the callback function (see previous posting). So far, this seems to work now.

Kind regards,
DAC324
Last edited by DAC324 on September 26th, 2013, 7:05 am, edited 1 time in total.

lithopsian
 
Posts: 3344
Joined: September 15th, 2010, 9:03 am

Post Posted September 26th, 2013, 6:37 am

The whole point of a callback is that it gets called back. Later! With a callback function this is enforced because you must pass a function and it will get called later.

A callback object is simply an object that contains a function, or at least a property which points to a function. In this case, a rather redundant object since there is only one function, but such a callback object could contain multiple function (methods in class-language-speak) as well as configuration data properties.

It is not necessary to have the object include self-creation and initialisation code as yours does, although this could be done if the function is different in different circumstances. It is certainly not acceptable for such constructor code to try and access the results of the callback, because they don't exist until the function his called back. Later!

So a callback object is simply:
Code: Select all
{onCompletion: function()
    {
        ...
        some callback code which has access to the livemark ID
        ...
    }
}


You won't find any Mozilla documentation explaining this because it is an inherent part of javascript. Find a javascript tutorial if you need to learn about the language itself. Or just peek into an addon that uses livemarks.

The inlined anonymous function I assigned to the onCompletion property in this example could equally be a named function external to the callback object. In fact if the callback is to be used very frequently this is probably desirable to eliminate frequent creation of functions which is a relatively expensive operation. For really advanced usage, the callback method could be prototyped and then instantiated with small differences for each use, although I'm not sure what the small differences might be in this case since it is just an object with a single method.
Last edited by lithopsian on September 26th, 2013, 8:46 am, edited 1 time in total.

DAC324
 
Posts: 144
Joined: October 19th, 2007, 1:54 am

Post Posted September 26th, 2013, 7:09 am

Dear lithopsian,

thank you very much. Coming from other languages, I first had to adapt to syntax constraints mainly. The tutorials in the net are mainly referring to callback functions only. So I had to read a lot before I could identify information useful for callback objects.

It seems that I now solved most of the understanding part :-)

Thank you once again,
DAC324

Return to Extension Development


Who is online

Users browsing this forum: No registered users and 1 guest