Create the simplest widget for Mac OS X Dashboard

  • Tutorial
Hello, habravchane-makovody!
Post picture
Today we will try to understand the basics of creating a widget for Dashboard in Mac OS X. We will need the Dashcode program, designed just for this.

First, a little theory. A widget in Dashboard is a specially formed web page packaged in a bundle along with all resources. Well, and a little official information in the appendage. Accordingly, the programming language used is JavaScript. If you are already familiar with it, as well as with HTML / CSS (although this is unlikely to be needed), then you are alreadyable to write a simple widget. If not, you should not be upset, this language is very simple and intuitive, you can deal with it quickly enough. Further I will consider that with JS the reader is more or less familiar. The article itself is designed for beginners, so please do not scold for "too simple a presentation and detailed chewing of elementary things." In addition, I ask you not to kick for the design either - well, I am not a designer, not a designer! If anyone wants to help with this matter - welcome =)

For convenience, all source codes (as well as a ready-to-use widget) are laid out on the github, link at the end of the article. But do not rush to just download them! It is better to spend a little time and figure out how to create it all yourself.

So let's get started. As a goal for experiments, of course, I chose our favorite Habr. We will step by step make a widget that displays karma, rating and position in the rating of ha-people of the chosen habruser.
A picture to attract attention
Such a widget (well, very similar) was already created by the neoromantic haberdasher already in 2007, but the download links are not working, and in addition, that article did not contain practical guidelines for creating such widgets.

Restore the right Replace these shortcomings.

Create an empty project. To do this, run Dashcode and click on the desired places. The process is trivial.

What do we see? The basic widget has the main and auxiliary states (front and back in the left panel, respectively). The first is displayed in normal operation mode, the second - to configure widget parameters. You can switch between them by selecting the appropriate items in the list of components on the left. We can safely remove everything superfluous, except for the “info” and “Done” buttons, which serve to switch between the main and auxiliary states. Further, for simplicity, we will call it the front and back sides of the widget.

Now, on the front side of our widget (without a single line of code!), We throw the necessary components: a few labels. To do this, open the component library - the Library button at the top right - and drag components of the "Text" type onto the widget. Now openInspector (also the button at the top right) and with its help we adjust the sizes, colors and so on for our widget. With its help, we will set meaningful names to our inscriptions - for more convenient access from the code.

On the back side we will throw an inscription and an input field. Well, and another picture - for beauty. And in the end we get something like this:



Well, not bad, our GUI is ready! We can press Cmd+Rand poke on the buttons (i) and Done, admiring the effect of flipping the widget.

But one GUI is not enough for us, so let's move on to the logic. To do this, click on the View button at the top left and select Source Code in the drop-down list. And we can already see our automatically generated JavaScript code. And we boldly begin to rule him!

First, let's decide on the "architecture" of our widget. We will use the timer to request user information through the Haber API, parse them and display karma and rating on the front side of the widget. To do this, declare a global variable updateTimerat the beginning of the main.js file, create functions startTimer(msec)and stopTimer()that will work with this timer. We also create a function updateStats()that will be called by timer.

function startTimer(msec)
{
    updateTimer = setTimeout("updateStats()", msec);
}
function stopTimer()
{
    clearTimeout(updateTimer);
}
function updateStats()
{
    alert("It works!");
    startTimer(updateInterval);
}

We will show()insert a call startTimer(5000)into the function to start the timer when the widget is displayed, and hide(), accordingly, we will insert the function stopTimer()to save resources when the widget is not shown (Dashboard is not active). Now we can launch our widget and see in the console (Cmd + Alt + 1) the output of “It works!” Every 5 seconds.

But we are not interested in such nonsense, we want to pull karma and rating on the timer! So in the function, updateStatus()instead of an alert, we will call the function execStatsRequest()(the Haber API advises against pulling user data more than once per minute, so at the same time we will increase the interval).

Now it's up to the HTTP requests to the habrahab API. We create new functions - execStatsRequest () and processStatsRequest (), which will serve to run and process requests. Here is how they look with me:
function execStatsRequest()
{
    if (userName().length > 0)
    {
        var Url = "http://habrahabr.ru/api/profile/" + userName() + "/";
        alert("User: " + userName() + "\nURL: " + Url);
        xmlHttp = new XMLHttpRequest(); 
        xmlHttp.onreadystatechange = processStatsRequest;
        xmlHttp.overrideMimeType('text/xml');
        xmlHttp.open("GET", Url, true);
        xmlHttp.send();
    }
    else
    {
        resetStats();
    }
}
function processStatsRequest()
{
    if (xmlHttp.readyState == 4 && xmlHttp.status == 200)
    {
        alert("xml is " + xmlHttp.responseXML);
        if (xmlHttp.responseXML == null)
        {
            resetStats();
        }
        else
        {
            alert(xmlHttp.responseText);
            var error = xmlHttp.responseXML.getElementsByTagName("error")[0];
            if (error != null)
            {
                alert("Some error occured!");
                resetStats();
                setLogin("<" + userName() + " not found>");
                return;
            }
            var login = xmlHttp.responseXML.getElementsByTagName("login")[0].firstChild.nodeValue;
            var karma = xmlHttp.responseXML.getElementsByTagName("karma")[0].firstChild.nodeValue;
            var rating = xmlHttp.responseXML.getElementsByTagName("rating")[0].firstChild.nodeValue;
            var position = xmlHttp.responseXML.getElementsByTagName("ratingPosition")[0].firstChild.nodeValue;
            setLogin(login);
            setKarma(karma);
            setRating(rating);
            setPosition(position);
        }                    
    }
}

Here we form the request URL, create an object of type XMLHttpRequest, and with its help we request our data using the GET method. What is noteworthy, we have to force the answer to the MIME type “text / xml” , because for some reason the Habra-api returns “text / html”. And in the function, processStatsRequest()we parse the response received in XML. At the same time, we check it for errors - and notify the user about it.

Here it is worthwhile to distract from the code and configure the widget itself - to allow it to work with the network. To do this, scroll down the list of elements in the left pane and see the Widget Attributes item. Here we just tick the “Allow Network Access” checkbox. You can also configure the widget id and its version. Now back to the code.

function setLogin(),setKarma()and others display the string transmitted to them in the desired fields of the front side. They were created for convenience and look the same, like this:

function setLogin(login)
{
    document.getElementById("userName").innerText = login;
}

The function resetStats()sets default values ​​for all fields. And the setUserName () and userName () functions serve as a wrapper over the input field for the name of the habrowser on the back of the widget:

function userName()
{
    return document.getElementById("nameEdit").value;
}
function setUserName(name)
{
    document.getElementById("nameEdit").value = name;
}

Well, the widget is almost ready. Why almost? Yes, because we would still have to save the entered username in the settings. To do this, we write the functions loadPrefs()and savePrefs().

var preferenceKey = "habraUserName";
function loadPrefs()
{
    var name = widget.preferenceForKey(widget.identifier + "-" + preferenceKey);
    alert(widget.identifier + "-" + preferenceKey);
    alert("name from preferences: " + name);
    if (name != null)
        setUserName(name);
}
function savePrefs()
{
    widget.setPreferenceForKey(userName(), widget.identifier + "-" + preferenceKey);
}

It is advisable to call these functions in the functions show()and hide(). The setting will be unique for each widget, which allows you to drop widgets with information on several users onto the Dashboard.

Well, now for sure the widget is ready for use. But there is no limit to perfection! We are now localizing our widget in order to have the Russian and English versions. You can also do (as your homework) localization in French and Japanese.

Going to our front side, we call the inspector. Now we select our inscriptions one by one and in the Localization section of the inspector we set the value in English in the Value field. They will probably coincide with the predefined values ​​of the Key field. These values ​​will be entered in the default (English) localization, which can be seen in the fileen.lproj/localizedStrings.js.

Now add the Russian localization. To the transitions to the Widget Attributes and in the Localization section, add (in the left list) the Russian language. We select it, and now in the right list we can enter localized strings.

These values, respectively, will be spelled out in ru.lproj/localizedStrings.js.

Actually, that’s all, we can launch our widget and enjoy our (or someone else's) karma! To install the widget in Dashboard, select Run & Share in the left panel and select Save to Disk or Deploy to Dashboard, depending on our needs.

If you want to download a ready-made widget, then you are welcome: here it is ! The source code of the project for Dashcode can be taken on the github .

I hope someone found this article useful and the list of widgets for Dashboard will be replenished with wonderful things!

Also popular now: