activityStream.js
Summary
This file contains an API for publishing to an activity stream partly based on http://activitystrea.ms/
The activity stream will be an Atom feed with the activity extension in the
"http://activitystrea.ms/spec/1.0/" namespace that can be used to programtically analyze the feed/p>
TODO: add example and more documentation
|
Class Summary
|
| ActivityModel |
An ActivityModel represents an activity entry in the stream. |
| ActivityObjectModel |
An ActivityObject model that is used for storing the data related to an ActivityObject
|
| ActivityStream |
The main interface for this library. |
if (! window["isArray"])
{
window["isArray"] = function() { return this != null && typeof this == "object" && 'splice' in this && 'join' in this;}
}
var ActivityVerbType =
{
Post : 1,
Share : 2,
Save : 3,
Favorite : 4,
View : 5,
Follow : 6,
UnFollow : 7,
MakeFriend : 8,
Join : 9,
Leave : 10,
Invite : 11
}
ActivityVerbType.toName = function(activityVerbType)
{
for (var o in ActivityVerbType)
{
if (ActivityVerbType[o] == activityVerbType)
{
return o;
}
}
return null;
}
ActivityVerbType.toUri = function(activityVerbType)
{
var name = ActivityVerbType.toName(activityVerbType);
var path = "";
if (name)
{
if (ActivityVerbType.MakeFriend == activityVerbType)
{
path = "make-friend";
}
else
{
path = name.toLowerCase();
}
}
if (name)
{
return "http://activitystrea.ms/schema/1.0/" + path;
}
else
{
return "";
}
}
var ActivityObjectType =
{
Article : 1,
BlogEntry : 2,
Note : 3,
File : 4,
Image : 5,
Photo : 6,
PhotoAlbum : 7,
PlayList : 8,
Video : 9,
TvEpisode : 10,
Movie : 11,
Audio : 12,
Bookmark : 13,
Person : 14,
Group : 15,
Place : 16
}
ActivityObjectType.toName = function(activityObjectType)
{
for (var o in ActivityObjectType)
{
if (ActivityObjectType[o] == activityObjectType)
{
return o;
}
}
return null;
}
ActivityObjectType.toUri = function(activityObjectType)
{
var name = ActivityObjectType.toName(activityObjectType);
var path = "";
switch (ActivityObjectType)
{
case ActivityObjectType.BlogEntry:
{
path = "blog-entry";
}
case ActivityObjectType.MakeFriend:
{
path = "make-friend";
}
case ActivityObjectType.PhotoAlbum:
{
path = "photo-album";
}
case ActivityObjectType.TvEpisode:
{
path = "tv-episode";
}
default:
{
if (name)
{
path = name.toLowerCase();
}
}
}
if (path)
{
return "http://activitystrea.ms/schema/1.0/" + path;
}
else
{
return "";
}
}
function ActivityObjectModel(type, title, link, metaData)
{
this.id = null;
this.type = type;
this.title = title;
this.link = link;
this.metaData = metaData;
}
function ActivityModel(title, verb, object, content)
{
this.title = title;
this.verb = verb ? verb : ActivityVerbType.Post;
this.object = object;
this.content = content;
this.id = null;
}
function ActivityStream()
{
if (ActivityStream.instance) {
return ActivityStream.instance;
}
else
{
ActivityStream.instance = this;
}
var _prefKey = "_activity_stream";
var _activityItems = [];
var _maxItems = 20;
var _idCounter = 0;
var webserver = opera.io.webserver;
var self = this;
function onPublishActivity(evt)
{
var request = evt.connection.request,
response = evt.connection.response;
var payLoad = request.getItem("payload");
self.publish(payLoad);
response.setStatusCode(200, "OK");
response.close();
}
function onGetActivityFeed(evt)
{
var request = evt.connection.request,
response = evt.connection.response;
response.setResponseHeader("Content-Type", "application/atom+xml")
response.write(self.getAtom());
response.close();
}
function onDeleteAllActivities(evt)
{
var request = evt.connection.request,
response = evt.connection.response;
widget.setPreferenceForKey("", _prefKey);
_activityItems = [];
response.setStatusCode(200, "OK");
response.write("Preferences deleted");
response.close();
}
function onGetStub(evt)
{
var request = evt.connection.request,
response = evt.connection.response;
response.close();
}
function zp(n)
{
return ("00"+n).slice(-2);
}
function getRfc3339Time(time)
{
if (! time)
{
time = new Date();
}
var tz = time.getTimezoneOffset() / 60;
var m = (tz/60 % 1) ? ":00" : ":30";
if (tz < 0)
{
tz = "+" + zp(-tz) + m;
}
else if (tz > 0)
{
tz = "-" + zp(tz) + m;
}
else
{
tz = "Z";
}
return time.getFullYear() + "-" + zp(time.getMonth()+1) + "-" + zp(time.getDate()) + "T" + zp(time.getHours()) + ":" + zp(time.getMinutes()) + ":" + zp(time.getSeconds()) + tz;
}
function init()
{
var tmpData = widget.preferenceForKey(_prefKey);
_idCounter = widget.preferenceForKey(_prefKey + "_counter");
if (! _idCounter)
{
_idCounter = 0;
}
_activityItems = (tmpData) ? JSON.parse(tmpData) : [];
}
function save()
{
if (_activityItems.length > _maxItems)
{
_activityItems = _activityItems.slice(_activityItems.length - _maxItems - 1);
}
var tmpData = JSON.stringify(_activityItems);
widget.setPreferenceForKey(tmpData, _prefKey);
widget.setPreferenceForKey(_idCounter, _prefKey + "_counter");
}
function getFeedUri()
{
return "http://" + webserver.hostName + webserver.currentServicePath;
}
function getEntryURI(activityItem)
{
return "tag:" + webserver.hostName + ",2009:" + activityItem.created;
}
function escapeHtml(string) {
if ( !string || !string.replace ) {return ''; }
return string.replace(/&/g, "&").replace(/</g, "<");
}
this.publish = function(title, verb, object, content)
{
var am = new ActivityModel(title, verb, object, content);
am.id = _idCounter++;
if (isArray(am.object))
{
for (var i = 0; i < am.object.length; i++)
{
am.object[i].id = _idCounter++;
}
}
else if (am.object)
{
am.object.id = _idCounter++;
}
am.created = am.updated = getRfc3339Time();
_activityItems.push(am);
save();
}
this.listen = function()
{
if (webserver)
{
webserver.addEventListener('activity', onGetActivityFeed, false);
webserver.addEventListener('activityDeleteAll', onDeleteAllActivities, false);
}
}
var pushActivityObject = function(a, obj)
{
a.push('<activity:object>');
a.push('<id>' + obj.id + '</id>');
a.push('<activity:object-type>' + escapeHtml(ActivityObjectType.toUri(obj.type)) + '</activity:object-type>');
if (obj.title)
{
a.push('<title>' + escapeHtml(obj.title) + '</title>');
}
if (obj.link)
{
a.push('<link rel="alternate" type="text/html" href="' + escapeHtml(obj.link) + '"/>');
}
if (obj.source)
{
a.push('<title>' + escapeHtml(obj.title) + '</title>');
}
a.push('</activity:object>');
}
this.getAtom = function()
{
var updated = _activityItems[0] ? _activityItems[_activityItems.length-1].updated : "2009-01-01T00:00:00Z";
var a = ['<?xml version="1.0" encoding="utf-8"?>',
'<feed xmlns="http://www.w3.org/2005/Atom" xmlns:activity="http://activitystrea.ms/spec/1.0/">',
'<title>' + escapeHtml(webserver.currentServiceName) + '</title>',
'<id>' + escapeHtml(getFeedUri()) + '</id>',
'<author><name>' + escapeHtml(webserver.userName) + '</name></author>',
'<updated>' + escapeHtml(updated) + '</updated>'];
for (var i = _activityItems.length - 1; i > -1 ;i--)
{
a.push('<entry>',
'<title>' + escapeHtml(_activityItems[i].title) + '</title>',
'<id>' + escapeHtml(getEntryURI(_activityItems[i])) + '</id>',
'<published>' + escapeHtml(_activityItems[i].created) + '</published>',
'<updated>' + escapeHtml(_activityItems[i].updated) + '</updated>');
if (isArray(_activityItems[i]['verb']))
{
for (var j = 0; j < _activityItems[i]['verb'].length; j++)
{
a.push('<activity:verb>' + escapeHtml(ActivityVerbType.toUri(_activityItems[i]['verb'][j])) + '</activity:verb>');
}
}
else
{
a.push('<activity:verb>' + escapeHtml(ActivityVerbType.toUri(_activityItems[i]['verb'])) + '</activity:verb>');
}
if (isArray(_activityItems[i]['object']))
{
for (var j = 0; j < _activityItems[i]['object'].length; j++)
{
pushActivityObject(a, _activityItems[i]['object'][j]);
}
}
else if (_activityItems[i]['object'])
{
pushActivityObject(a, _activityItems[i]['object']);
}
if (_activityItems[i]['content'])
{
a.push('<content type="html"><![CDATA[' + _activityItems[i]['content'] + ']]></content>');
}
else
{
a.push('<content type="html"><![CDATA[]]></content>');
}
a.push('</entry>');
}
a.push('</feed>');
return a.join('\n');
}
init();
}
Documentation generated by
JSDoc on Thu Nov 26 16:10:17 2009