O meu Widget Eis o código do meu primeiro widget que figura no meu Mac
Onde me permite receber os RSS deste mesmo site ... xKoisas
Coloco todo este código para:
- Para que todos aqueles que não imaginam como é que os programas são feitos possam ter uma ideia.
-Para todos aqueles que já sabem como os computadores funcionam perceberem um pouco do potencial de programação do Mac.
Eis o ambiente onde foi programado o Widget

Feito no DashCode (Aplicação que a Apple por desleixo distribuiu junto com DVD do sistema operativo (Mac OS X), entregue com os últimos portáteis MacBook Pro)
e eis o código que faz com que o programa seja:
(tudo o que está escrito após as // são os comentários que os programadores colocam para se orientarem sempre que necessitem rever ou alterar o código do programa. Essas informações não são tidas em conta pelo compilador (ferramenta que serve para pegar neste código e converter o mesmo num programa para que o computador o entenda como tal).
var initKeyPrefix = "apple-init-";
var htmlFeedURL = null;
var feedURLKey = "feedURL";
var numItemsToShow = 1;
var numItemsToShowKey = "numItemsToShow";
var maxAgeToShowKey = "maxAgeToShow";
var maxAgeToShow = 0;
var showDateKey = "showDate";
var showDate = 1;
var feed = { url: null, title: "" };
var newFeedURL = null;
var feedAdded = false;
var last_updated = 0;
var xml_request = null;
var slider;
function load()
{
numItemsToShow = getPropertyFromHTML(numItemsToShowKey, numItemsToShow);
maxAgeToShow = getPropertyFromHTML(maxAgeToShowKey, maxAgeToShow);
showDate = getPropertyFromHTML(showDateKey, showDate);
slider = document.getElementById("slider");
if (window.widget) {
htmlFeedURL = getFeedSource();
feed.url = htmlFeedURL;
setFeedURL(feed.url);
}
}
function remove()
{
// your widget has just been removed from the layer
// remove any preferences as needed
}
function hide()
{
// your widget has just been hidden stop any timers to
// prevent cpu usage
}
function show()
{
// your widget has just been shown. restart any timers
// and adjust your interface as needed
var now = (new Date).getTime();
// only check if 15 minutes have passed
if ((now - last_updated) > 900000) {
if (xml_request != null) {
xml_request.abort();
xml_request = null;
}
xml_request = new XMLHttpRequest();
xml_request.onload = function(e) {xml_loaded(e, xml_request);}
xml_request.overrideMimeType("text/xml");
xml_request.open("GET", feed.url);
xml_request.setRequestHeader("Cache-Control", "no-cache");
xml_request.send(null);
}
}
function showBack(event)
{
// your widget needs to show the back
var front = document.getElementById("front");
var back = document.getElementById("back");
if (window.widget)
widget.prepareForTransition("ToBack");
front.style.display="none";
back.style.display="block";
if (window.widget)
setTimeout('widget.performTransition();', 0);
}
function showFront(event)
{
// your widget needs to show the front
var front = document.getElementById("front");
var back = document.getElementById("back");
if (window.widget)
widget.prepareForTransition("ToFront");
front.style.display="block";
back.style.display="none";
if (window.widget)
setTimeout('widget.performTransition();', 0);
scrollArea.refresh();
}
if (window.widget) {
widget.onremove = remove;
widget.onhide = hide;
widget.onshow = show;
}
// Retrieve the contents of an HTML div
function getPropertyFromHTML(propertyKey, defaultValue)
{
var element = document.getElementById(initKeyPrefix + propertyKey);
if (element) {
return trim(element.innerHTML);
}
else {
return defaultValue;
}
}
function getFeedSource()
{
var url = getPropertyFromHTML(feedURLKey);
if (url) {
if (url.substring(0,7).toLowerCase() != "http://") {
url = "http://" + url;
}
}
return url;
}
function findChild(element, nodeName)
{
var child;
for (child = element.firstChild; child != null; child = child.nextSibling) {
if (child.nodeName == nodeName)
return child;
}
return null;
}
function xml_loaded (e, request)
{
xml_request = null;
if (request.responseXML) {
var contents = document.getElementById('content');
// Remove the old entries
removeEntriesFromContents(contents);
// Get the top level element
var feedRootElement = request.responseXML.documentElement;
if (!feedRootElement) { alert("no root element"); return; }
var results;
if (feedRootElement.tagName.toLowerCase() == "feed") {
//&& feedRootElement.namespaceURI == "http://www.w3.org/2005/Atom") {
results = getAtomFeed(feedRootElement);
}
else if (feedRootElement.tagName.toLowerCase() == "rss") {
results = getRSSFeed(feedRootElement);
}
// Got no results?
if (results == null || results.length < 1)
return;
if (feed.url.indexOf("phobos.apple.com") != -1) {
// iTunes demo, sort by Title
results.sort(compTop10Func);
} else {
// sort by date
results.sort (compFunc);
}
// Limit entries to top N, etc.
results = filterEntries(results);
// Generate the display
addEntriesToContents(contents, results);
// update the scrollbar so scrollbar matches new data
scrollArea.refresh();
// set last_updated to the current time to keep track of the last time a request was posted
last_updated = (new Date).getTime();
}
}
function removeEntriesFromContents(contents)
{
while (contents.hasChildNodes()) {
contents.removeChild(contents.firstChild);
}
}
function addEntriesToContents(contents, entries)
{
// copy title and date into rows for display. Store link so it can be used when user
// clicks on title
nItems = entries.length;
var even = true;
for (var i = 0; i < nItems; ++i) {
var item = entries[i];
var row = createRow (item.title, item.link, item.date, item.description, even);
even = !even;
contents.appendChild (row);
}
}
function filterEntries(entries)
{
var result = new Array();
var cutoffDate = null;
if (maxAgeToShow) {
cutoffDate = new Date((new Date()).getTime() - maxAgeToShow);
}
for (var i = 0; i < numItemsToShow; i++) {
var entry = entries[i];
var entryDate = entry.date;
if (entryDate == null) {
// No date, pretend it's today
entryDate = new Date();
}
if (cutoffDate == null || entryDate >= cutoffDate) {
result.push(entry);
}
}
return result;
}
// Correct hyperlinks in a document fragment to use the openURL function
function fixLinks(htmlFragment)
{
// Collect all the links
var links = htmlFragment.getElementsByTagName("a");
for (var i = 0; i < links.length; i++) {
var aNode = links[i];
// Send them to our clickOnLink function
aNode.onclick = clickOnLink;
}
}
// XXX - http://delete.me.uk/2005/03/iso8601.html
// XXX - license unclear, discuss or replace
Date.prototype.setISO8601 = function (string) {
var regexp = "([0-9]{4})(-([0-9]{2})(-([0-9]{2})" +
"(T([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?" +
"(Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?";
var d = string.match(new RegExp(regexp));
var offset = 0;
var date = new Date(d[1], 0, 1);
if (d[3]) { date.setMonth(d[3] - 1); }
if (d[5]) { date.setDate(d[5]); }
if (d[7]) { date.setHours(d[7]); }
if (d[8]) { date.setMinutes(d[8]); }
if (d[10]) { date.setSeconds(d[10]); }
if (d[12]) { date.setMilliseconds(Number("0." + d[12]) * 1000); }
if (d[14]) {
offset = (Number(d[16]) * 60) + Number(d[17]);
offset *= ((d[15] == '-') ? 1 : -1);
}
offset -= date.getTimezoneOffset();
time = (Number(date) + (offset * 60 * 1000));
this.setTime(Number(time));
}
function getAtomFeed(atom)
{
var results = new Array;
// Get all entry elements subordinate to the channel element
// For each element, get title, link and publication date.
// Note that all elements of an item are optional.
for(var item = atom.firstChild; item != null; item = item.nextSibling) {
if( item.nodeName == 'entry' ) {
var title = findChild(item, 'title');
// we have to have the title to include the item in the list
if( title != null ) {
// Just get the first link for now - Atom is complicated
var link;
var linkElement = findChild(item, 'link');
if (linkElement) {
link = linkElement.getAttribute("href");
}
// Try a few different ways to find a date
var pubDate;
var updatedElement = findChild(item, 'updated');
if (updatedElement == null) { updatedElement = findChild(item, "issued"); }
if (updatedElement == null) { updatedElement = findChild(item, "modified"); }
if (updatedElement == null) { updatedElement = findChild(item, "created"); }
if (updatedElement) {
pubDate = new Date;
pubDate.setISO8601(updatedElement.firstChild.data);
}
var description = findChild(item, 'summary');
if (description == null) { description = findChild(item, 'content'); }
if (description != null) {
// XXX - In Atom, description is a DOM tree; this could use some rethinking
var xmlSerializer = new XMLSerializer();
description = xmlSerializer.serializeToString(description);
}
results[results.length] = {title:title.firstChild.data,
link:link,
date:pubDate,
description:description
}
}
}
}
return results;
}
function getRSSFeed(rss)
{
// Get single subordinate channel element
var channel = findChild( rss, 'channel');
if (!channel) {alert("no element"); return;}
var results = new Array;
// Get all item elements subordinate to the channel element
// For each element, get title, link and publication date.
// Note that all elements of an item are optional.
for(var item = channel.firstChild; item != null; item = item.nextSibling) {
if( item.nodeName == 'item' ) {
var title = findChild(item, 'title');
// we have to have the title to include the item in the list
if( title != null ) {
var link = findChild(item, 'link');
var pubDate = findChild(item, 'pubDate');
if (pubDate) {
pubDate = pubDate.firstChild.data;
}
if (pubDate && feed.url.indexOf("http://www.washingtonpost.com") == 0) {
var dArray = pubDate.split(/\s/);
pubDate = dArray[0] + " " + dArray[1] + " " + dArray[2] + " " + dArray[5] + " " + dArray[3] + " " + dArray[4];
}
var description = findChild(item, 'description');
results[results.length] = {title:title.firstChild.data,
link:(link != null ? link.firstChild.data : null),
date:(pubDate != null ? new Date(Date.parse(pubDate)) : null),
description:(description != null ? description.firstChild.data : null)
}
}
}
}
return results;
}
function compTop10Func(a, b)
{
var aInt = parseInt(a.title);
var bInt = parseInt(b.title);
if (aInt < bInt)
return -1;
else if (aInt > bInt)
return 1;
else
return 0;
}
function compTitleFunc(a, b)
{
if (a.title < b.title)
return -1;
else if (a.title > b.title)
return 1;
else
return 0;
}
function compFunc(a, b)
{
if (a.date < b.date)
return 1;
else if (a.date > b.date)
return -1;
else
return 0;
}
function createRow (title, link, date, description, even)
{
var article = document.createElement('div');
article.setAttribute('class', 'article ' + (even ? "even" : "odd"));
var articlefooter = document.createElement('div');
articlefooter.setAttribute('class', 'articlefooter');
article.appendChild(articlefooter);
var articlehead = document.createElement('a');
articlehead.setAttribute('class', 'articlehead');
if (link != null) {
articlehead.setAttribute('the_link', link);
articlehead.setAttribute('onclick', 'clickOnTitle(event, this);');
articlehead.setAttribute('href', '#');
}
var subject_div = document.createElement('div');
subject_div.setAttribute('class', 'subject');
subject_div.innerText = title;
articlehead.appendChild(subject_div);
if (date != null) {
var date_div = document.createElement('div');
date_div.setAttribute ('class', 'date');
if (showDate == 1) {
date_div.innerText = createDateStr(date);
}
articlehead.appendChild(date_div);
}
article.appendChild(articlehead);
if (description != null) {
var desc_div = document.createElement('div');
desc_div.setAttribute('class', 'articlebody');
desc_div.innerHTML = description;
// Clean up hyperlinks
fixLinks(desc_div);
article.appendChild(desc_div);
}
return article;
}
function createDateStr (date)
{
var month;
switch (date.getMonth()) {
case 0: month = 'Jan'; break;
case 1: month = 'Feb'; break;
case 2: month = 'Mar'; break;
case 3: month = 'Apr'; break;
case 4: month = 'May'; break;
case 5: month = 'Jun'; break;
case 6: month = 'Jul'; break;
case 7: month = 'Aug'; break;
case 8: month = 'Sep'; break;
case 9: month = 'Oct'; break;
case 10: month = 'Nov'; break;
case 11: month = 'Dec'; break;
}
return month + ' ' + date.getDate();
}
// Open in the browser instead of in the widget
function clickOnLink()
{
if (window.widget) {
widget.openURL(this.href);
return false;
}
}
function clickOnTitle(event, div)
{
if (window.widget) {
widget.openURL(div.the_link);
}
}
function clickOnFeedTitle(event)
{
if (window.widget) {
widget.openURL(feed.url);
}
}
function setFeedURL(newURL)
{
newFeedURL = newURL;
}
function scaleArticles( value )
{
var content = document.getElementById('content');
content.style.appleLineClamp = value + "%";
}
function endScale()
{
//scrollArea.refresh();
}
function scaleTo( value ) {
slider.value = value;
scaleArticles( value );
}
function scaleToMin() {
scaleTo( slider.min);
}
function scaleToMax() {
scaleTo( slider.max );
}