You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@shindig.apache.org by li...@apache.org on 2010/10/07 17:54:40 UTC
svn commit: r1005506 [4/45] - in /shindig/branches/2.0.x: ./ content/editor/
content/editor/CodeMirror-0.8/ content/editor/CodeMirror-0.8/css/
content/editor/CodeMirror-0.8/js/ content/samplecontainer/examples/media/
etc/ etc/checkstyle/ extras/src/mai...
Added: shindig/branches/2.0.x/content/samplecontainer/examples/media/MediaUI.js
URL: http://svn.apache.org/viewvc/shindig/branches/2.0.x/content/samplecontainer/examples/media/MediaUI.js?rev=1005506&view=auto
==============================================================================
--- shindig/branches/2.0.x/content/samplecontainer/examples/media/MediaUI.js (added)
+++ shindig/branches/2.0.x/content/samplecontainer/examples/media/MediaUI.js Thu Oct 7 15:54:09 2010
@@ -0,0 +1,524 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+
+/*
+ * The User Interface for the Albums & MediaItems gadget.
+ *
+ * SHINDIG TODOS
+ * set ownerId automatically?
+ * delete children mediaitems when album deleted?
+ * update only updates given fields?
+ * update album mediaitem count when inserting/removing mediaitem?
+ *
+ * GADGET TODOS
+ * album info such as how many albums are contained
+ * fix auto height for edit album popup
+ * thumnail pictures
+ */
+function MediaUI(social) {
+ var viewer = null;
+ var divManager = null;
+
+ var folderUrl = "http://www.clker.com/cliparts/2/b/b/3/1194983972976950993blue_folder_seth_yastrov_01.svg.med.png";
+ var docUrl = "http://www.plastyc.com/images/document-icon.png";
+
+ /*
+ * Initializes the gadget.
+ */
+ this.init = function() {
+ console.log("initializing AlbumsUI");
+
+ // Manages high-level divs
+ divManager = new DivManager();
+ divManager.init();
+
+ // Load data and render
+ loadData(function() {
+ social.getAlbumsByUser(viewer.id, function(response) {
+ renderAlbums(response.list);
+ divManager.showAlbums();
+ });
+ });
+ }
+
+ /*
+ * Pre-load data for gadget.
+ */
+ function loadData(callback) {
+ social.getViewer(function(data) {
+ viewer = data;
+ callback();
+ });
+ }
+
+ /*
+ * Manages the gadgets main DIV elements.
+ *
+ * TODO: use dojo.query() & classes rather than divs[]
+ * TODO: showOnly() function to avoid flashing/pauses
+ */
+ function DivManager() {
+ var divs = [];
+
+ this.init = function() {
+ console.log('DivManager.init');
+ addDiv('albumsDiv');
+ addDiv('mediaItemsDiv');
+ addDiv('mediaItemDiv');
+ hideAll();
+ }
+
+ this.showAlbums = function() {
+ console.log('DivManager.showAlbums');
+ hideAll();
+ divs['albumsDiv'].style.display = 'block';
+ this.refreshWindow();
+ }
+
+ this.showMediaItems = function() {
+ console.log('DivManager.showMediaItems');
+ hideAll();
+ divs['mediaItemsDiv'].style.display = 'block';
+ this.refreshWindow();
+ }
+
+ this.showMediaItem = function() {
+ console.log('DivManager.showMediaItem');
+ hideAll();
+ divs['mediaItemDiv'].style.display = 'block';
+ this.refreshWindow();
+ }
+
+ this.refreshWindow = function() {
+ gadgets.window.adjustHeight(500);
+ }
+
+ function hideAll() {
+ for (key in divs) { divs[key].style.display = 'none'; }
+ }
+
+ function addDiv(id) { divs[id] = dojo.create('div', {id: id}, dojo.body()); }
+ }
+
+ /*
+ * Renders a list of the given albums.
+ */
+ function renderAlbums(albums) {
+ console.log('renderAlbums');
+
+ dojo.empty('albumsDiv');
+ var albumsDiv = dojo.byId('albumsDiv');
+
+ var albumsBanner = dojo.create('div', null, albumsDiv);
+ var table = dojo.create('table', null, albumsBanner);
+ var tbody = dojo.create('tbody', null, table);
+ var tr = dojo.create('tr', null, tbody);
+ dojo.create('td', {innerHTML: viewer.name.formatted + "'s Albums", className: 'albumsTitle'}, tr);
+ dojo.create('td', null, tr).appendChild(new dijit.form.Button({label: '+ New Album', onClick: dojo.hitch(this, editAlbumPopup, null)}).domNode);
+
+ var albumsList = dojo.create('div', null, albumsDiv);
+ if (albums.length > 0) {
+ var table = dojo.create('table', {className: 'albumsTable'}, albumsList);
+ var tbody = dojo.create('tbody', null, table);
+ for (i = 0; i < albums.length; i++) {
+ var albumRow = dojo.create('tr', null, tbody);
+ var albumLeft = dojo.create('td', {className: 'albumListThumbnail'}, albumRow);
+ var imgLink = dojo.create('a', {href: "javascript:;", onclick: dojo.hitch(this, onClickAlbum, viewer.id, albums[i])}, albumLeft);
+ dojo.create('img', {src: albums[i].thumbnailUrl, onerror: "this.src='" + folderUrl + "';", width: '100%'}, imgLink);
+ var albumRight = dojo.create('td', {className: 'albumListRight'}, albumRow);
+ var albumTitleRow = dojo.create('tr', null, albumRight);
+ var titleTd = dojo.create('td', {className: 'albumListTitle'}, albumTitleRow);
+ dojo.create('a', {innerHTML: albums[i].title, href: 'javascript:;', onclick: dojo.hitch(this, onClickAlbum, viewer.id, albums[i])}, titleTd);
+ var editTd = dojo.create('td', {className: 'actionLinks', style: 'text-align: right'}, albumTitleRow);
+ dojo.create('a', {innerHTML: 'edit', href: 'javascript:;', onclick: dojo.hitch(this, editAlbumPopup, albums[i])}, editTd);
+ editTd.appendChild(dojo.doc.createTextNode(' | '));
+ dojo.create('a', {innerHTML: 'delete', href: 'javascript:;', onclick: dojo.hitch(this, deleteAlbumPopup, albums[i])}, editTd);
+ if (albums[i].description) {
+ var albumDescription = dojo.create('tr', null, albumRight);
+ dojo.create('td', {innerHTML: albums[i].description, className: 'albumListDescription', colspan: '2'}, albumDescription);
+ }
+ //var albumInfo = dojo.create('tr', null, albumRight);
+ //var infoStr = "ID: " + albums[i].id + " | Owner ID: " + albums[i].ownerId;
+ //dojo.create('td', {innerHTML: infoStr, className: 'albumListInfo', colspan: '2'}, albumInfo);
+ }
+ } else {
+ albumsDiv.appendChild(dojo.doc.createTextNode("No albums found."));
+ }
+ divManager.refreshWindow();
+
+ // Handles when user clicks an album
+ function onClickAlbum(userId, album) {
+ social.getMediaItemsByAlbum(userId, album.id, function(response) {
+ renderMediaItems(album, response.list);
+ divManager.showMediaItems();
+ });
+ }
+ }
+
+ /*
+ * Convenience function to retrieve albums and render.
+ */
+ function renderAlbumsByUser(userId, callback) {
+ social.getAlbumsByUser(userId, function(response) {
+ renderAlbums(response.list);
+ divManager.showAlbums();
+ if (callback != null) callback();
+ });
+ }
+
+ /*
+ * Renders a grid of the given MediaItems.
+ *
+ * TODO: simplify this by simply taking in 'album', retrieving MediaItems here
+ */
+ function renderMediaItems(album, mediaItems) {
+ console.log('renderMediaItems');
+ dojo.empty('mediaItemsDiv');
+ var mediaItemsDiv = dojo.byId('mediaItemsDiv');
+ var numCols = 5;
+
+ // Div to display navation bar and Create button
+ var topDiv = dojo.create('div', null, mediaItemsDiv);
+ var table = dojo.create('table', null, topDiv);
+ var tbody = dojo.create('tbody', null, table);
+ var tr = dojo.create('tr', null, tbody);
+ var td = dojo.create('td', {style: 'width:100%'}, tr);
+ dojo.create('a', {innerHTML: 'Albums', href: 'javascript:;', onclick: dojo.hitch(this, renderAlbumsByUser, viewer.id, null)}, td);
+ td.appendChild(dojo.doc.createTextNode(' > ' + album.title));
+ td = dojo.create('td', {style: 'width:100%'}, tr);
+ var createButton = new dijit.form.Button({label: '+ New MediaItem', onClick: dojo.hitch(this, editMediaItemPopup, album, null)});
+ td.appendChild(createButton.domNode);
+
+ // Div to display MediaItems in a grid
+ var gridDiv = dojo.create('div', null, mediaItemsDiv);
+ if (mediaItems.length > 0) {
+ var table = dojo.create('table', null, gridDiv);
+ var tbody = dojo.create('tbody', null, table);
+ var tr = null;
+ for (i = 0; i < mediaItems.length; i++) {
+ if (i % numCols == 0) {
+ tr = dojo.create('tr', null, tbody);
+ }
+ var td = dojo.create('td', {className: 'mediaItemBox'}, tr);
+ var imageTd = dojo.create('tr', null, td).appendChild(dojo.create('td', {className: 'mediaItemThumbnail'}));
+ if (mediaItems[i].url) {
+ var imageLink = dojo.create('a', {href: "javascript:;", onclick: dojo.hitch(this, renderMediaItem, album, mediaItems[i])}, imageTd);
+ imageLink.appendChild(dojo.create('img', {src: mediaItems[i].thumbnailUrl, onerror: "this.src='" + docUrl + "';", style:'height:100px;'}));
+ } else {
+ dojo.create('img', {src: mediaItems[i].thumbnailUrl, onerror: "this.src='" + docUrl + "';", style:'height:100px;'}, imageTd);
+ }
+ var titleTd = dojo.create('tr', null, td).appendChild(dojo.create('td', {style: "text-align:center; font-family:'comic sans ms';white-space:nowrap;"}));
+ titleTd.appendChild(dojo.doc.createTextNode(mediaItems[i].title));
+ var actionsTd = dojo.create('tr', null, td).appendChild(dojo.create('td', {className: 'actionLinks', style: 'text-align: center;'}));
+ dojo.create('a', {innerHTML: 'edit', href: 'javascript:;', onclick: dojo.hitch(this, editMediaItemPopup, album, mediaItems[i])}, actionsTd);
+ actionsTd.appendChild(dojo.doc.createTextNode(' | '));
+ dojo.create('a', {innerHTML: 'delete', href: 'javascript:;', onclick: dojo.hitch(this, deleteMediaItemPopup, album, mediaItems[i])}, actionsTd);
+ }
+ } else {
+ gridDiv.appendChild(dojo.doc.createTextNode('Album is empty'));
+ }
+ divManager.refreshWindow();
+ }
+
+ /*
+ * Convenience function to retriev & render MediaItems by Album.
+ */
+ function retrieveAndRenderMediaItems(album) {
+ social.getMediaItemsByAlbum(viewer.id, album.id, function(response) {
+ divManager.showMediaItems();
+ renderMediaItems(album, response.list);
+ });
+ }
+
+ /*
+ * Renders the view for a single MediaItem.
+ */
+ function renderMediaItem(album, mediaItem) {
+ console.log('renderMediaItem');
+ dojo.empty('mediaItemDiv');
+ var mediaItemDiv = dojo.byId('mediaItemDiv');
+
+ // Div to display navation bar and Create button
+ var topDiv = dojo.create('div', null, mediaItemDiv);
+ var table = dojo.create('table', null, topDiv);
+ var tbody = dojo.create('tbody', null, table);
+ var tr = dojo.create('tr', null, tbody);
+ var td = dojo.create('td', {style: 'width:100%'}, tr);
+ dojo.create('a', {innerHTML: 'Albums', href: 'javascript:;', onclick: dojo.hitch(this, renderAlbumsByUser, viewer.id, null)}, td);
+ td.appendChild(dojo.doc.createTextNode(" > "));
+ dojo.create('a', {innerHTML: album.title, href: "javascript:;", onclick: dojo.hitch(this, retrieveAndRenderMediaItems, album)}, td);
+ td.appendChild(dojo.doc.createTextNode(" > " + mediaItem.title));
+
+ // Div to show MediaItem
+ var itemDiv = dojo.create('div', null, mediaItemDiv);
+ var table = dojo.create('table', null, itemDiv);
+ var tbody = dojo.create('tbody', null, table);
+ var tr = dojo.create('tr', null, tbody);
+ var td = dojo.create('td', null, tr);
+ dojo.create('img', {src: mediaItem.url}, td);
+ if (mediaItem.description) {
+ tr = dojo.create('tr', null, tbody);
+ td = dojo.create('td', null, tr);
+ td.appendChild(dojo.doc.createTextNode(mediaItem.description));
+ }
+
+ divManager.showMediaItem();
+ }
+
+ /*
+ * Popup to edit album.
+ */
+ function editAlbumPopup(album) {
+ console.log('editAlbumPopup: ' + JSON.stringify(album));
+
+ var title = (album == null ? 'Create' : 'Edit') + ' Album';
+ var dialog = new dijit.Dialog({id: 'editAlbumPopup', title: title, onCancel: destroyDialog});
+ dojo.body().appendChild(dialog.domNode);
+
+ var formDiv = dojo.create('div', {id: 'editAlbumFormDiv'});
+ var form = new dijit.form.Form({id: 'editAlbumForm'});
+ formDiv.appendChild(form.domNode);
+ var table = dojo.create('table', null, form.domNode);
+ var tbody = dojo.create('tbody', null, table);
+ var tr = dojo.create('tr', null, tbody);
+ dojo.create('td', null, tr).appendChild(dojo.create('label', {innerHTML: 'Title', for: 'title'}));
+ dojo.create('td', null, tr).appendChild(
+ new dijit.form.ValidationTextBox({
+ name: 'title',
+ value: album == null ? '' : album.title
+ }).domNode
+ );
+ tr = dojo.create('tr', null, tbody);
+ dojo.create('td', null, tr).appendChild(dojo.create('label', {innerHTML: 'Thumnail URL', for: 'thumbnail'}));
+ dojo.create('td', null, tr).appendChild(
+ new dijit.form.ValidationTextBox({
+ name: 'thumbnail',
+ value: album == null ? '' : album.thumbnailUrl
+ }).domNode
+ );
+ tr = dojo.create('tr', null, tbody);
+ dojo.create('td', null, tr).appendChild(dojo.create('label', {innerHTML: 'Description', for: 'description'}));
+ dojo.create('td', null, tr).appendChild(
+ new dijit.form.Textarea({
+ name: 'description',
+ value: album == null ? '' : album.description
+ }).domNode
+ );
+ tr = dojo.create('tr', null, tbody);
+ var buttonTd = dojo.create('td', {colspan: '2', align: 'center'}, tr);
+ buttonTd.appendChild(new dijit.form.Button({
+ label: 'Save',
+ onClick: saveForm
+ }).domNode
+ );
+ buttonTd.appendChild(new dijit.form.Button({
+ label: 'Cancel',
+ onClick: destroyDialog
+ }).domNode
+ );
+
+ dialog.set('content', formDiv);
+ dialog.show();
+
+ function saveForm() {
+ console.log('saveForm');
+ var values = form.get('value');
+ var newAlbum = {
+ title: values.title,
+ thumbnailUrl: values.thumbnail,
+ description: values.description,
+ ownerId: viewer.id // TODO: bug? Albums service should set this
+ };
+ if (album == null) {
+ social.createAlbum(viewer.id, newAlbum, function(response) {
+ console.log('created album response: ' + JSON.stringify(response));
+ renderAlbumsByUser(viewer.id);
+ });
+ } else {
+ social.updateAlbum(viewer.id, album.id, newAlbum, function(response) {
+ console.log('updated album response: ' + JSON.stringify(response));
+ renderAlbumsByUser(viewer.id);
+ });
+ }
+ destroyDialog();
+ }
+
+ // Handles destroying the dialog popup
+ function destroyDialog() {
+ console.log('destroyDialog');
+ dialog.destroyRecursive(false);
+ dialog.destroyRendering(false);
+ dialog.destroy(false);
+ }
+ }
+
+ /*
+ * Popup to edit MediaItem.
+ */
+ function editMediaItemPopup(album, mediaItem) {
+ console.log('editMediaItemPopup: ' + JSON.stringify(mediaItem));
+
+ var albumId = mediaItem == null ? album.id : mediaItem.albumId;
+ var title = (mediaItem == null ? 'Create' : 'Edit') + ' MediaItem';
+ var dialog = new dijit.Dialog({id: 'editMediaItemPopup', title: title, onCancel: destroyDialog});
+ dojo.body().appendChild(dialog.domNode);
+
+ // Form div
+ var formDiv = dojo.create('div', {id: 'editMediaItemFormDiv'});
+ var form = new dijit.form.Form({id: 'editMediaItemForm'});
+ formDiv.appendChild(form.domNode);
+ var table = dojo.create('table', null, form.domNode);
+ var tbody = dojo.create('tbody', null, table);
+ var tr = dojo.create('tr', null, tbody);
+ dojo.create('td', null, tr).appendChild(dojo.create('label', {innerHTML: 'Title', for: 'title'}));
+ dojo.create('td', null, tr).appendChild(
+ new dijit.form.ValidationTextBox({
+ name: 'title',
+ value: mediaItem == null ? '' : mediaItem.title
+ }).domNode
+ );
+ tr = dojo.create('tr', null, tbody);
+ dojo.create('td', null, tr).appendChild(dojo.create('label', {innerHTML: 'Description', for: 'description'}));
+ dojo.create('td', null, tr).appendChild(
+ new dijit.form.Textarea({
+ name: 'description',
+ value: mediaItem == null ? '' : mediaItem.description
+ }).domNode
+ );
+ tr = dojo.create('tr', null, tbody);
+ dojo.create('td', null, tr).appendChild(dojo.create('label', {innerHTML: 'Type', for: 'type'}));
+ dojo.create('td', null, tr).appendChild(
+ new dijit.form.ValidationTextBox({
+ name: 'type',
+ value: mediaItem == null ? '' : mediaItem.type
+ }).domNode
+ );
+ tr = dojo.create('tr', null, tbody);
+ dojo.create('td', null, tr).appendChild(dojo.create('label', {innerHTML: 'Thumnail URL', for: 'thumbnailUrl'}));
+ dojo.create('td', null, tr).appendChild(
+ new dijit.form.ValidationTextBox({
+ name: 'thumbnailUrl',
+ value: mediaItem == null ? '' : mediaItem.thumbnailUrl
+ }).domNode
+ );
+ tr = dojo.create('tr', null, tbody);
+ dojo.create('td', null, tr).appendChild(dojo.create('label', {innerHTML: 'URL', for: 'url'}));
+ dojo.create('td', null, tr).appendChild(
+ new dijit.form.ValidationTextBox({
+ name: 'url',
+ value: mediaItem == null ? '' : mediaItem.url
+ }).domNode
+ );
+ tr = dojo.create('tr', null, tbody);
+ var buttonTd = dojo.create('td', {colspan: '2', align: 'center'}, tr);
+ buttonTd.appendChild(new dijit.form.Button({
+ label: 'Save',
+ onClick: saveForm
+ }).domNode
+ );
+ buttonTd.appendChild(new dijit.form.Button({
+ label: 'Cancel',
+ onClick: destroyDialog
+ }).domNode
+ );
+
+ // Textarea div for JSON
+ var textAreaDiv = dojo.create('div', {style: "width:100%; height:100%;", id: 'textAreaDiv'});
+ var textArea = new dijit.form.Textarea({value: JSON.stringify(mediaItem), rows: "20"});
+ textAreaDiv.appendChild(textArea.domNode);
+
+ // Put divs together
+ var tabContainer = new dijit.layout.TabContainer({style: "width:400px; height:300px;"});
+ var formContentPane = new dijit.layout.ContentPane({title: "Form", content: formDiv});
+ tabContainer.addChild(formContentPane);
+ var textAreaContentPane = new dijit.layout.ContentPane({title: "JSON", content: textAreaDiv});
+ tabContainer.addChild(textAreaContentPane);
+ tabContainer.startup();
+ var dialogDiv = dojo.create('div', null);
+ dialogDiv.appendChild(tabContainer.domNode);
+
+ dialog.set('content', dialogDiv);
+ dialog.show();
+
+ function saveForm() {
+ console.log('saveForm mediaItem');
+ var values = form.get('value');
+ var newMediaItem = {
+ title: values.title,
+ description: values.description,
+ type: values.type,
+ thumbnailUrl: values.thumbnailUrl,
+ url: values.url
+ };
+ if (newMediaItem.type == null || newMediaItem.type == "") newMediaItem.type = "image";
+ if (mediaItem == null) {
+ social.createMediaItem(viewer.id, albumId, newMediaItem, function(response) {
+ console.log('created MediaItem response: ' + JSON.stringify(response));
+ social.getMediaItemsByAlbum(viewer.id, album.id, function(response) {
+ renderMediaItems(album, response.list);
+ });
+ });
+ } else {
+ social.updateMediaItem(viewer.id, albumId, mediaItem.id, newMediaItem, function(response) {
+ console.log('updated MediaItem response: ' + JSON.stringify(response));
+ social.getMediaItemsByAlbum(viewer.id, album.id, function(response) {
+ renderMediaItems(album, response.list);
+ });
+ });
+ }
+ destroyDialog();
+ }
+
+ // Handles destroying the dialog popup
+ function destroyDialog() {
+ console.log('destroyDialog');
+ dialog.destroyRecursive(false);
+ dialog.destroyRendering(false);
+ dialog.destroy(false);
+ }
+ }
+
+ /*
+ * Popup to confirm that the user wants to delete album.
+ */
+ function deleteAlbumPopup(album) {
+ console.log('deleteAlbumPopup');
+ if (confirm("Delete '" + album.title + "'?")) {
+ social.deleteAlbum(viewer.id, album.id, function(response) {
+ console.log('delete album response: ' + JSON.stringify(response));
+ renderAlbumsByUser(viewer.id);
+ });
+ }
+ }
+
+ /*
+ * Popup to confirm user wants to delete MediaItem.
+ */
+ function deleteMediaItemPopup(album, mediaItem) {
+ console.log('deleteMediaItemPopup');
+ var albumId = mediaItem.albumId;
+ if (confirm("Delete '" + mediaItem.title + "'?")) {
+ social.deleteMediaItem(viewer.id, albumId, mediaItem.id, function(response) {
+ console.log('delete mediaItem response: ' + JSON.stringify(response));
+ social.getMediaItemsByAlbum(viewer.id, albumId, function(response) {
+ renderMediaItems(album, response.list);
+ });
+ });
+ }
+ }
+}
\ No newline at end of file
Added: shindig/branches/2.0.x/content/samplecontainer/examples/media/Social.js
URL: http://svn.apache.org/viewvc/shindig/branches/2.0.x/content/samplecontainer/examples/media/Social.js?rev=1005506&view=auto
==============================================================================
--- shindig/branches/2.0.x/content/samplecontainer/examples/media/Social.js (added)
+++ shindig/branches/2.0.x/content/samplecontainer/examples/media/Social.js Thu Oct 7 15:54:09 2010
@@ -0,0 +1,156 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+
+/*
+ * Defines high level functionality to interact with the OpenSocial API.
+ */
+function SocialWrapper() {
+
+ /*
+ * Retrieves the current viewer.
+ */
+ this.getViewer = function(callback) {
+ osapi.people.getViewer().execute(callback);
+ }
+
+ /*
+ * Retrieves the current owner.
+ */
+ this.getOwner = function(callback) {
+ osapi.people.getOwner().execute(callback);
+ }
+
+ //------------------------ ALBUMS ----------------------
+ /*
+ * Retrieves albums by ID(s).
+ */
+ this.getAlbumsById = function(userId, albumId, callback) {
+ var params = {userId: userId, albumId: albumId};
+ osapi.albums.get(params).execute(callback);
+ }
+
+ /*
+ * Retrieves albums by user.
+ */
+ this.getAlbumsByUser = function(userId, callback) {
+ osapi.albums.get({userId: userId}).execute(callback);
+ }
+
+ /*
+ * Retrieves albums by group.
+ */
+ this.getAlbumsByGroup = function(userId, groupId, callback) {
+ osapi.albums.get({userId: userId, groupId: groupId}).execute(callback);
+ }
+
+ /*
+ * Creates an album for the given user.
+ */
+ this.createAlbum = function(userId, album, callback) {
+ var params = {
+ userId: userId,
+ album: album
+ };
+ osapi.albums.create(params).execute(callback);
+ }
+
+ /*
+ * Updates an album by ID.
+ */
+ this.updateAlbum = function(userId, albumId, album, callback) {
+ var params = {
+ userId: userId,
+ albumId: albumId,
+ album: album
+ };
+ osapi.albums.update(params).execute(callback);
+ }
+
+ /*
+ * Deletes an album by ID.
+ */
+ this.deleteAlbum = function(userId, albumId, callback) {
+ var params = {userId: userId, albumId: albumId};
+ osapi.albums.delete(params).execute(callback);
+ }
+
+ //------------------------------- MEDIAITEMS ----------------------------
+ /*
+ * Creates a MediaItem.
+ */
+ this.createMediaItem = function(userId, albumId, mediaItem, callback) {
+ var params = {
+ userId: userId,
+ albumId: albumId,
+ mediaItem: mediaItem
+ };
+ osapi.mediaItems.create(params).execute(callback);
+ }
+
+ /*
+ * Updates a MediaItem by ID.
+ */
+ this.updateMediaItem = function(userId, albumId, mediaItemId, mediaItem, callback) {
+ var params = {
+ userId: userId,
+ albumId: albumId,
+ mediaItemId: mediaItemId,
+ mediaItem: mediaItem
+ };
+ console.log("PARAMS: " + JSON.stringify(params));
+ osapi.mediaItems.update(params).execute(callback);
+ }
+
+ /*
+ * Retrieves MediaItems by ID(s).
+ */
+ this.getMediaItemsById = function(userId, albumId, mediaItemId, callback) {
+ var params = {
+ userId: userId,
+ albumId: albumId,
+ mediaItemId: mediaItemId
+ };
+ osapi.mediaItems.get(params).execute(callback);
+ }
+
+ /*
+ * Retrieves MediaItems by album.
+ */
+ this.getMediaItemsByAlbum = function(userId, albumId, callback) {
+ osapi.mediaItems.get({userId: userId, albumId: albumId}).execute(callback);
+ }
+
+ /*
+ * Retrieves MediaItems by user and group.
+ */
+ this.getMediaItemsByUser = function(userId, groupId, callback) {
+ osapi.mediaItems.get({userId: userId, groupId: groupId}).execute(callback);
+ }
+
+ /*
+ * Deletes a MediaItem by ID.
+ */
+ this.deleteMediaItem = function(userId, albumId, mediaItemId, callback) {
+ var params = {
+ userId: userId,
+ albumId: albumId,
+ mediaItemId: mediaItemId
+ };
+ osapi.mediaItems.delete(params).execute(callback);
+ }
+}
\ No newline at end of file
Added: shindig/branches/2.0.x/content/samplecontainer/examples/media/styles.css
URL: http://svn.apache.org/viewvc/shindig/branches/2.0.x/content/samplecontainer/examples/media/styles.css?rev=1005506&view=auto
==============================================================================
--- shindig/branches/2.0.x/content/samplecontainer/examples/media/styles.css (added)
+++ shindig/branches/2.0.x/content/samplecontainer/examples/media/styles.css Thu Oct 7 15:54:09 2010
@@ -0,0 +1,110 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+
+/* ============ ROUND 2 ============== */
+
+td.albumsTitle {
+ font-family:'comic sans ms';
+ width: 100%;
+ font-size:24px;
+}
+
+td.albumListThumbnail {
+ width: 10%;
+ height: 75px;
+}
+
+td.albumListRight {
+ width: 90%;
+}
+
+td.actionLinks {
+ width:100%;
+ font-size:12px;
+}
+
+td.albumListTitle {
+ font-size:24px;
+ white-space:nowrap;
+ font-family:'comic sans ms';
+}
+
+td.albumListDescription {
+ font-family:'comic sans ms';
+}
+
+.albumsTable {
+ width:100%;
+ border-style:solid;
+ background-color:#b0c4de;
+}
+
+td.mediaItemThumbnail {
+ height:100%;
+}
+
+td.mediaItemBox {
+ width: 150px;
+ height: 100px;
+}
+
+.mediaItemControls {
+
+}
+
+
+/* ============ ROUND 1 ============== */
+.temp1 {background-color:#6495ed;}
+.temp2 {background-color:#e0ffff;}
+.temp3 {
+ background-color:#b0c4de;
+ background-image:url('img_flwr.png');
+ background-repeat:no-repeat;
+ background-position:top right;
+}
+
+td2 {
+ border-style:solid;
+}
+
+td.albumLeft {
+ width:10%;
+}
+
+td.albumRight {
+ width: 90%;
+}
+
+
+
+td.albumEdit {
+ width:100%;
+ text-align:right;
+ vertical-align:middle;
+ font-size:12px;
+}
+
+
+
+.albumTitleStyle {
+ color: blue;
+
+}
+.albumElement {
+ background-color:#b0c4de;
+}
Modified: shindig/branches/2.0.x/etc/checkstyle/checkstyle.xml
URL: http://svn.apache.org/viewvc/shindig/branches/2.0.x/etc/checkstyle/checkstyle.xml?rev=1005506&r1=1005505&r2=1005506&view=diff
==============================================================================
--- shindig/branches/2.0.x/etc/checkstyle/checkstyle.xml (original)
+++ shindig/branches/2.0.x/etc/checkstyle/checkstyle.xml Thu Oct 7 15:54:09 2010
@@ -52,6 +52,10 @@ under the License.
<module name="Checker">
+ <module name="LineLength">
+ <property name="max" value="100"/>
+ </module>
+
<!-- Checks that a package.html file exists for each package. -->
<!-- See http://checkstyle.sf.net/config_javadoc.html#PackageHtml -->
<module name="PackageHtml">
Added: shindig/branches/2.0.x/etc/run-gjslint
URL: http://svn.apache.org/viewvc/shindig/branches/2.0.x/etc/run-gjslint?rev=1005506&view=auto
==============================================================================
--- shindig/branches/2.0.x/etc/run-gjslint (added)
+++ shindig/branches/2.0.x/etc/run-gjslint Thu Oct 7 15:54:09 2010
@@ -0,0 +1,2 @@
+#!/bin/sh
+gjslint --strict --unix_mode --exclude_directories features/src/main/javascript/features/swfobject,features/src/main/javascript/features/i18n --recurse features/src/main/javascript/features
Propchange: shindig/branches/2.0.x/etc/run-gjslint
------------------------------------------------------------------------------
svn:executable = *
Modified: shindig/branches/2.0.x/etc/set_svn_properties.sh
URL: http://svn.apache.org/viewvc/shindig/branches/2.0.x/etc/set_svn_properties.sh?rev=1005506&r1=1005505&r2=1005506&view=diff
==============================================================================
--- shindig/branches/2.0.x/etc/set_svn_properties.sh (original)
+++ shindig/branches/2.0.x/etc/set_svn_properties.sh Thu Oct 7 15:54:09 2010
@@ -33,6 +33,7 @@
#svn propset svn:ignore -F etc/svn-ignores java/social-api
#svn propset svn:ignore -F etc/svn-ignores java/server
#svn propset svn:ignore -F etc/svn-ignores java/samples
+#svn propset svn:ignore -F etc/svn-ignores php
# Language files
find . -name "*.java" | grep -v '.svn' | xargs -n 1 svn propset svn:eol-style native
Modified: shindig/branches/2.0.x/extras/src/main/java/org/apache/shindig/extras/as/opensocial/service/ActivityStreamsHandler.java
URL: http://svn.apache.org/viewvc/shindig/branches/2.0.x/extras/src/main/java/org/apache/shindig/extras/as/opensocial/service/ActivityStreamsHandler.java?rev=1005506&r1=1005505&r2=1005506&view=diff
==============================================================================
--- shindig/branches/2.0.x/extras/src/main/java/org/apache/shindig/extras/as/opensocial/service/ActivityStreamsHandler.java (original)
+++ shindig/branches/2.0.x/extras/src/main/java/org/apache/shindig/extras/as/opensocial/service/ActivityStreamsHandler.java Thu Oct 7 15:54:09 2010
@@ -42,7 +42,7 @@ import com.google.inject.Inject;
* <p>ActivityStreamsHandler class.</p>
*
*/
-@Service(name = "activitystreams", path="/{userId}+/{groupId}/{appId}/{activitystream}/{activityEntryId}+")
+@Service(name = "activitystreams", path="/{userId}+/{groupId}/{appId}/{activityEntryId}+")
public class ActivityStreamsHandler {
private final ActivityStreamService service;
Modified: shindig/branches/2.0.x/extras/src/main/javascript/features-extras/features.txt
URL: http://svn.apache.org/viewvc/shindig/branches/2.0.x/extras/src/main/javascript/features-extras/features.txt?rev=1005506&r1=1005505&r2=1005506&view=diff
==============================================================================
--- shindig/branches/2.0.x/extras/src/main/javascript/features-extras/features.txt (original)
+++ shindig/branches/2.0.x/extras/src/main/javascript/features-extras/features.txt Thu Oct 7 15:54:09 2010
@@ -20,4 +20,4 @@ features-extras/org.jquery.core-1.4.2/fe
features-extras/wave/feature.xml
features-extras/opensocial-payment/feature.xml
features-extras/pubsub-2/feature.xml
-features-extras/org.openajax.hub-2.0.4/feature.xml
+features-extras/org.openajax.hub-2.0.5/feature.xml
Added: shindig/branches/2.0.x/extras/src/main/javascript/features-extras/org.openajax.hub-2.0.5/OpenAjax-mashup.js
URL: http://svn.apache.org/viewvc/shindig/branches/2.0.x/extras/src/main/javascript/features-extras/org.openajax.hub-2.0.5/OpenAjax-mashup.js?rev=1005506&view=auto
==============================================================================
--- shindig/branches/2.0.x/extras/src/main/javascript/features-extras/org.openajax.hub-2.0.5/OpenAjax-mashup.js (added)
+++ shindig/branches/2.0.x/extras/src/main/javascript/features-extras/org.openajax.hub-2.0.5/OpenAjax-mashup.js Thu Oct 7 15:54:09 2010
@@ -0,0 +1,1357 @@
+/*******************************************************************************
+ * OpenAjax-mashup.js
+ *
+ * Reference implementation of the OpenAjax Hub, as specified by OpenAjax Alliance.
+ * Specification is under development at:
+ *
+ * http://www.openajax.org/member/wiki/OpenAjax_Hub_Specification
+ *
+ * Copyright 2006-2009 OpenAjax Alliance
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy
+ * of the License at http://www.apache.org/licenses/LICENSE-2.0 . Unless
+ * required by applicable law or agreed to in writing, software distributed
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ *
+ ******************************************************************************/
+
+var OpenAjax = OpenAjax || {};
+
+if ( !OpenAjax.hub ) { // prevent re-definition of the OpenAjax.hub object
+
+OpenAjax.hub = function() {
+ var libs = {};
+ var ooh = "org.openajax.hub.";
+
+ return /** @scope OpenAjax.hub */ {
+ implementer: "http://openajax.org",
+ implVersion: "2.0.5",
+ specVersion: "2.0",
+ implExtraData: {},
+ libraries: libs,
+
+ registerLibrary: function(prefix, nsURL, version, extra) {
+ libs[prefix] = {
+ prefix: prefix,
+ namespaceURI: nsURL,
+ version: version,
+ extraData: extra
+ };
+ this.publish(ooh+"registerLibrary", libs[prefix]);
+ },
+
+ unregisterLibrary: function(prefix) {
+ this.publish(ooh+"unregisterLibrary", libs[prefix]);
+ delete libs[prefix];
+ }
+ };
+}();
+
+/**
+ * Error
+ *
+ * Standard Error names used when the standard functions need to throw Errors.
+ */
+OpenAjax.hub.Error = {
+ // Either a required argument is missing or an invalid argument was provided
+ BadParameters: "OpenAjax.hub.Error.BadParameters",
+ // The specified hub has been disconnected and cannot perform the requested
+ // operation:
+ Disconnected: "OpenAjax.hub.Error.Disconnected",
+ // Container with specified ID already exists:
+ Duplicate: "OpenAjax.hub.Error.Duplicate",
+ // The specified ManagedHub has no such Container (or it has been removed)
+ NoContainer: "OpenAjax.hub.Error.NoContainer",
+ // The specified ManagedHub or Container has no such subscription
+ NoSubscription: "OpenAjax.hub.Error.NoSubscription",
+ // Permission denied by manager's security policy
+ NotAllowed: "OpenAjax.hub.Error.NotAllowed",
+ // Wrong communications protocol identifier provided by Container or HubClient
+ WrongProtocol: "OpenAjax.hub.Error.WrongProtocol",
+ // A 'tunnelURI' param was specified, but current browser does not support security features
+ IncompatBrowser: "OpenAjax.hub.Error.IncompatBrowser"
+};
+
+/**
+ * SecurityAlert
+ *
+ * Standard codes used when attempted security violations are detected. Unlike
+ * Errors, these codes are not thrown as exceptions but rather passed into the
+ * SecurityAlertHandler function registered with the Hub instance.
+ */
+OpenAjax.hub.SecurityAlert = {
+ // Container did not load (possible frame phishing attack)
+ LoadTimeout: "OpenAjax.hub.SecurityAlert.LoadTimeout",
+ // Hub suspects a frame phishing attack against the specified container
+ FramePhish: "OpenAjax.hub.SecurityAlert.FramePhish",
+ // Hub detected a message forgery that purports to come to a specified
+ // container
+ ForgedMsg: "OpenAjax.hub.SecurityAlert.ForgedMsg"
+};
+
+/**
+ * Debugging Help
+ *
+ * OpenAjax.hub.enableDebug
+ *
+ * If OpenAjax.hub.enableDebug is set to true, then the "debugger" keyword
+ * will get hit whenever a user callback throws an exception, thereby
+ * bringing up the JavaScript debugger.
+ */
+OpenAjax.hub._debugger = function() {
+// if ( OpenAjax.hub.enableDebug ) debugger; // REMOVE ON BUILD
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Hub interface
+ *
+ * Hub is implemented on the manager side by ManagedHub and on the client side
+ * by ClientHub.
+ */
+//OpenAjax.hub.Hub = function() {}
+
+/**
+ * Subscribe to a topic.
+ *
+ * @param {String} topic
+ * A valid topic string. MAY include wildcards.
+ * @param {Function} onData
+ * Callback function that is invoked whenever an event is
+ * published on the topic
+ * @param {Object} [scope]
+ * When onData callback or onComplete callback is invoked,
+ * the JavaScript "this" keyword refers to this scope object.
+ * If no scope is provided, default is window.
+ * @param {Function} [onComplete]
+ * Invoked to tell the client application whether the
+ * subscribe operation succeeded or failed.
+ * @param {*} [subscriberData]
+ * Client application provides this data, which is handed
+ * back to the client application in the subscriberData
+ * parameter of the onData callback function.
+ *
+ * @returns subscriptionID
+ * Identifier representing the subscription. This identifier is an
+ * arbitrary ID string that is unique within this Hub instance
+ * @type {String}
+ *
+ * @throws {OpenAjax.hub.Error.Disconnected} if this Hub instance is not in CONNECTED state
+ * @throws {OpenAjax.hub.Error.BadParameters} if the topic is invalid (e.g. contains an empty token)
+ */
+//OpenAjax.hub.Hub.prototype.subscribe = function( topic, onData, scope, onComplete, subscriberData ) {}
+
+/**
+ * Publish an event on a topic
+ *
+ * @param {String} topic
+ * A valid topic string. MUST NOT include wildcards.
+ * @param {*} data
+ * Valid publishable data. To be portable across different
+ * Container implementations, this value SHOULD be serializable
+ * as JSON.
+ *
+ * @throws {OpenAjax.hub.Error.Disconnected} if this Hub instance is not in CONNECTED state
+ * @throws {OpenAjax.hub.Error.BadParameters} if the topic cannot be published (e.g. contains
+ * wildcards or empty tokens) or if the data cannot be published (e.g. cannot be serialized as JSON)
+ */
+//OpenAjax.hub.Hub.prototype.publish = function( topic, data ) {}
+
+/**
+ * Unsubscribe from a subscription
+ *
+ * @param {String} subscriptionID
+ * A subscriptionID returned by Hub.subscribe()
+ * @param {Function} [onComplete]
+ * Callback function invoked when unsubscribe completes
+ * @param {Object} [scope]
+ * When onComplete callback function is invoked, the JavaScript "this"
+ * keyword refers to this scope object.
+ * If no scope is provided, default is window.
+ *
+ * @throws {OpenAjax.hub.Error.Disconnected} if this Hub instance is not in CONNECTED state
+ * @throws {OpenAjax.hub.Error.NoSubscription} if no such subscription is found
+ */
+//OpenAjax.hub.Hub.prototype.unsubscribe = function( subscriptionID, onComplete, scope ) {}
+
+/**
+ * Return true if this Hub instance is in the Connected state.
+ * Else returns false.
+ *
+ * This function can be called even if the Hub is not in a CONNECTED state.
+ *
+ * @returns Boolean
+ * @type {Boolean}
+ */
+//OpenAjax.hub.Hub.prototype.isConnected = function() {}
+
+/**
+ * Returns the scope associated with this Hub instance and which will be used
+ * with callback functions.
+ *
+ * This function can be called even if the Hub is not in a CONNECTED state.
+ *
+ * @returns scope object
+ * @type {Object}
+ */
+//OpenAjax.hub.Hub.prototype.getScope = function() {}
+
+/**
+ * Returns the subscriberData parameter that was provided when
+ * Hub.subscribe was called.
+ *
+ * @param {String} subscriptionID
+ * The subscriberID of a subscription
+ *
+ * @returns subscriberData
+ * @type {*}
+ *
+ * @throws {OpenAjax.hub.Error.Disconnected} if this Hub instance is not in CONNECTED state
+ * @throws {OpenAjax.hub.Error.NoSubscription} if there is no such subscription
+ */
+//OpenAjax.hub.Hub.prototype.getSubscriberData = function(subscriptionID) {}
+
+/**
+ * Returns the scope associated with a specified subscription. This scope will
+ * be used when invoking the 'onData' callback supplied to Hub.subscribe().
+ *
+ * @param {String} subscriberID
+ * The subscriberID of a subscription
+ *
+ * @returns scope
+ * @type {*}
+ *
+ * @throws {OpenAjax.hub.Error.Disconnected} if this Hub instance is not in CONNECTED state
+ * @throws {OpenAjax.hub.Error.NoSubscription} if there is no such subscription
+ */
+//OpenAjax.hub.Hub.prototype.getSubscriberScope = function(subscriberID) {}
+
+/**
+ * Returns the params object associated with this Hub instance.
+ *
+ * @returns params
+ * The params object associated with this Hub instance
+ * @type {Object}
+ */
+//OpenAjax.hub.Hub.prototype.getParameters = function() {}
+
+////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * HubClient interface
+ *
+ * Extends Hub interface.
+ *
+ * A HubClient implementation is typically specific to a particular
+ * implementation of Container.
+ */
+
+/**
+ * Create a new HubClient. All HubClient constructors MUST have this
+ * signature.
+ * @constructor
+ *
+ * @param {Object} params
+ * Parameters used to instantiate the HubClient.
+ * Once the constructor is called, the params object belongs to the
+ * HubClient. The caller MUST not modify it.
+ * Implementations of HubClient may specify additional properties
+ * for the params object, besides those identified below.
+ *
+ * @param {Function} params.HubClient.onSecurityAlert
+ * Called when an attempted security breach is thwarted
+ * @param {Object} [params.HubClient.scope]
+ * Whenever one of the HubClient's callback functions is called,
+ * references to "this" in the callback will refer to the scope object.
+ * If not provided, the default is window.
+ * @param {Function} [params.HubClient.log]
+ * Optional logger function. Would be used to log to console.log or
+ * equivalent.
+ *
+ * @throws {OpenAjax.hub.Error.BadParameters} if any of the required
+ * parameters is missing, or if a parameter value is invalid in
+ * some way.
+ */
+//OpenAjax.hub.HubClient = function( params ) {}
+
+/**
+ * Requests a connection to the ManagedHub, via the Container
+ * associated with this HubClient.
+ *
+ * If the Container accepts the connection request, the HubClient's
+ * state is set to CONNECTED and the HubClient invokes the
+ * onComplete callback function.
+ *
+ * If the Container refuses the connection request, the HubClient
+ * invokes the onComplete callback function with an error code.
+ * The error code might, for example, indicate that the Container
+ * is being destroyed.
+ *
+ * In most implementations, this function operates asynchronously,
+ * so the onComplete callback function is the only reliable way to
+ * determine when this function completes and whether it has succeeded
+ * or failed.
+ *
+ * A client application may call HubClient.disconnect and then call
+ * HubClient.connect.
+ *
+ * @param {Function} [onComplete]
+ * Callback function to call when this operation completes.
+ * @param {Object} [scope]
+ * When the onComplete function is invoked, the JavaScript "this"
+ * keyword refers to this scope object.
+ * If no scope is provided, default is window.
+ *
+ * @throws {OpenAjax.hub.Error.Duplicate} if the HubClient is already connected
+ */
+//OpenAjax.hub.HubClient.prototype.connect = function( onComplete, scope ) {}
+
+/**
+ * Disconnect from the ManagedHub
+ *
+ * Disconnect immediately:
+ *
+ * 1. Sets the HubClient's state to DISCONNECTED.
+ * 2. Causes the HubClient to send a Disconnect request to the
+ * associated Container.
+ * 3. Ensures that the client application will receive no more
+ * onData or onComplete callbacks associated with this
+ * connection, except for the disconnect function's own
+ * onComplete callback.
+ * 4. Automatically destroys all of the HubClient's subscriptions.
+ *
+ * In most implementations, this function operates asynchronously,
+ * so the onComplete callback function is the only reliable way to
+ * determine when this function completes and whether it has succeeded
+ * or failed.
+ *
+ * A client application is allowed to call HubClient.disconnect and
+ * then call HubClient.connect.
+ *
+ * @param {Function} [onComplete]
+ * Callback function to call when this operation completes.
+ * @param {Object} [scope]
+ * When the onComplete function is invoked, the JavaScript "this"
+ * keyword refers to the scope object.
+ * If no scope is provided, default is window.
+ *
+ * @throws {OpenAjax.hub.Error.Disconnected} if the HubClient is already
+ * disconnected
+ */
+//OpenAjax.hub.HubClient.prototype.disconnect = function( onComplete, scope ) {}
+
+/**
+ * If DISCONNECTED: Returns null
+ * If CONNECTED: Returns the origin associated with the window containing the
+ * Container associated with this HubClient instance. The origin has the format
+ *
+ * [protocol]://[host]
+ *
+ * where:
+ *
+ * [protocol] is "http" or "https"
+ * [host] is the hostname of the partner page.
+ *
+ * @returns Partner's origin
+ * @type {String}
+ */
+//OpenAjax.hub.HubClient.prototype.getPartnerOrigin = function() {}
+
+/**
+ * Returns the client ID of this HubClient
+ *
+ * @returns clientID
+ * @type {String}
+ */
+//OpenAjax.hub.HubClient.prototype.getClientID = function() {}
+
+////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * OpenAjax.hub.ManagedHub
+ *
+ * Managed hub API for the manager application and for Containers.
+ *
+ * Implements OpenAjax.hub.Hub.
+ */
+
+/**
+ * Create a new ManagedHub instance
+ * @constructor
+ *
+ * This constructor automatically sets the ManagedHub's state to
+ * CONNECTED.
+ *
+ * @param {Object} params
+ * Parameters used to instantiate the ManagedHub.
+ * Once the constructor is called, the params object belongs exclusively to
+ * the ManagedHub. The caller MUST not modify it.
+ *
+ * The params object may contain the following properties:
+ *
+ * @param {Function} params.onPublish
+ * Callback function that is invoked whenever a
+ * data value published by a Container is about
+ * to be delivered to some (possibly the same) Container.
+ * This callback function implements a security policy;
+ * it returns true if the delivery of the data is
+ * permitted and false if permission is denied.
+ * @param {Function} params.onSubscribe
+ * Called whenever a Container tries to subscribe
+ * on behalf of its client.
+ * This callback function implements a security policy;
+ * it returns true if the subscription is permitted
+ * and false if permission is denied.
+ * @param {Function} [params.onUnsubscribe]
+ * Called whenever a Container unsubscribes on behalf of its client.
+ * Unlike the other callbacks, onUnsubscribe is intended only for
+ * informative purposes, and is not used to implement a security
+ * policy.
+ * @param {Object} [params.scope]
+ * Whenever one of the ManagedHub's callback functions is called,
+ * references to the JavaScript "this" keyword in the callback
+ * function refer to this scope object
+ * If no scope is provided, default is window.
+ * @param {Function} [params.log] Optional logger function. Would
+ * be used to log to console.log or equivalent.
+ *
+ * @throws {OpenAjax.hub.Error.BadParameters} if any of the required
+ * parameters are missing
+ */
+OpenAjax.hub.ManagedHub = function( params )
+{
+ if ( ! params || ! params.onPublish || ! params.onSubscribe )
+ throw new Error( OpenAjax.hub.Error.BadParameters );
+
+ this._p = params;
+ this._onUnsubscribe = params.onUnsubscribe ? params.onUnsubscribe : null;
+ this._scope = params.scope || window;
+
+ if ( params.log ) {
+ var that = this;
+ this._log = function( msg ) {
+ try {
+ params.log.call( that._scope, "ManagedHub: " + msg );
+ } catch( e ) {
+ OpenAjax.hub._debugger();
+ }
+ };
+ } else {
+ this._log = function() {};
+ }
+
+ this._subscriptions = { c:{}, s:null };
+ this._containers = {};
+
+ // Sequence # used to create IDs that are unique within this hub
+ this._seq = 0;
+
+ this._active = true;
+
+ this._isPublishing = false;
+ this._pubQ = [];
+}
+
+/**
+ * Subscribe to a topic on behalf of a Container. Called only by
+ * Container implementations, NOT by manager applications.
+ *
+ * This function:
+ * 1. Checks with the ManagedHub's onSubscribe security policy
+ * to determine whether this Container is allowed to subscribe
+ * to this topic.
+ * 2. If the subscribe operation is permitted, subscribes to the
+ * topic and returns the ManagedHub's subscription ID for this
+ * subscription.
+ * 3. If the subscribe operation is not permitted, throws
+ * OpenAjax.hub.Error.NotAllowed.
+ *
+ * When data is published on the topic, the ManagedHub's
+ * onPublish security policy will be invoked to ensure that
+ * this Container is permitted to receive the published data.
+ * If the Container is allowed to receive the data, then the
+ * Container's sendToClient function will be invoked.
+ *
+ * When a Container needs to create a subscription on behalf of
+ * its client, the Container MUST use this function to create
+ * the subscription.
+ *
+ * @param {OpenAjax.hub.Container} container
+ * A Container
+ * @param {String} topic
+ * A valid topic
+ * @param {String} containerSubID
+ * Arbitrary string ID that the Container uses to
+ * represent the subscription. Must be unique within the
+ * context of the Container
+ *
+ * @returns managerSubID
+ * Arbitrary string ID that this ManagedHub uses to
+ * represent the subscription. Will be unique within the
+ * context of this ManagedHub
+ * @type {String}
+ *
+ * @throws {OpenAjax.hub.Error.Disconnected} if this.isConnected() returns false
+ * @throws {OpenAjax.hub.Error.NotAllowed} if subscription request is denied by the onSubscribe security policy
+ * @throws {OpenAjax.hub.Error.BadParameters} if one of the parameters, e.g. the topic, is invalid
+ */
+OpenAjax.hub.ManagedHub.prototype.subscribeForClient = function( container, topic, containerSubID )
+{
+ this._assertConn();
+ // check subscribe permission
+ if ( this._invokeOnSubscribe( topic, container ) ) {
+ // return ManagedHub's subscriptionID for this subscription
+ return this._subscribe( topic, this._sendToClient, this, { c: container, sid: containerSubID } );
+ }
+ throw new Error(OpenAjax.hub.Error.NotAllowed);
+}
+
+/**
+ * Unsubscribe from a subscription on behalf of a Container. Called only by
+ * Container implementations, NOT by manager application code.
+ *
+ * This function:
+ * 1. Destroys the specified subscription
+ * 2. Calls the ManagedHub's onUnsubscribe callback function
+ *
+ * This function can be called even if the ManagedHub is not in a CONNECTED state.
+ *
+ * @param {OpenAjax.hub.Container} container
+ * container instance that is unsubscribing
+ * @param {String} managerSubID
+ * opaque ID of a subscription, returned by previous call to subscribeForClient()
+ *
+ * @throws {OpenAjax.hub.Error.NoSubscription} if subscriptionID does not refer to a valid subscription
+ */
+OpenAjax.hub.ManagedHub.prototype.unsubscribeForClient = function( container, managerSubID )
+{
+ this._unsubscribe( managerSubID );
+ this._invokeOnUnsubscribe( container, managerSubID );
+}
+
+/**
+ * Publish data on a topic on behalf of a Container. Called only by
+ * Container implementations, NOT by manager application code.
+ *
+ * @param {OpenAjax.hub.Container} container
+ * Container on whose behalf data should be published
+ * @param {String} topic
+ * Valid topic string. Must NOT contain wildcards.
+ * @param {*} data
+ * Valid publishable data. To be portable across different
+ * Container implementations, this value SHOULD be serializable
+ * as JSON.
+ *
+ * @throws {OpenAjax.hub.Error.Disconnected} if this.isConnected() returns false
+ * @throws {OpenAjax.hub.Error.BadParameters} if one of the parameters, e.g. the topic, is invalid
+ */
+OpenAjax.hub.ManagedHub.prototype.publishForClient = function( container, topic, data )
+{
+ this._assertConn();
+ this._publish( topic, data, container );
+}
+
+/**
+ * Destroy this ManagedHub
+ *
+ * 1. Sets state to DISCONNECTED. All subsequent attempts to add containers,
+ * publish or subscribe will throw the Disconnected error. We will
+ * continue to allow "cleanup" operations such as removeContainer
+ * and unsubscribe, as well as read-only operations such as
+ * isConnected
+ * 2. Remove all Containers associated with this ManagedHub
+ */
+OpenAjax.hub.ManagedHub.prototype.disconnect = function()
+{
+ this._active = false;
+ for (var c in this._containers) {
+ this.removeContainer( this._containers[c] );
+ }
+}
+
+/**
+ * Get a container belonging to this ManagedHub by its clientID, or null
+ * if this ManagedHub has no such container
+ *
+ * This function can be called even if the ManagedHub is not in a CONNECTED state.
+ *
+ * @param {String} containerId
+ * Arbitrary string ID associated with the container
+ *
+ * @returns container associated with given ID
+ * @type {OpenAjax.hub.Container}
+ */
+OpenAjax.hub.ManagedHub.prototype.getContainer = function( containerId )
+{
+ var container = this._containers[containerId];
+ return container ? container : null;
+}
+
+/**
+ * Returns an array listing all containers belonging to this ManagedHub.
+ * The order of the Containers in this array is arbitrary.
+ *
+ * This function can be called even if the ManagedHub is not in a CONNECTED state.
+ *
+ * @returns container array
+ * @type {OpenAjax.hub.Container[]}
+ */
+OpenAjax.hub.ManagedHub.prototype.listContainers = function()
+{
+ var res = [];
+ for (var c in this._containers) {
+ res.push(this._containers[c]);
+ }
+ return res;
+}
+
+/**
+ * Add a container to this ManagedHub.
+ *
+ * This function should only be called by a Container constructor.
+ *
+ * @param {OpenAjax.hub.Container} container
+ * A Container to be added to this ManagedHub
+ *
+ * @throws {OpenAjax.hub.Error.Duplicate} if there is already a Container
+ * in this ManagedHub whose clientId is the same as that of container
+ * @throws {OpenAjax.hub.Error.Disconnected} if this.isConnected() returns false
+ */
+OpenAjax.hub.ManagedHub.prototype.addContainer = function( container )
+{
+ this._assertConn();
+ var containerId = container.getClientID();
+ if ( this._containers[containerId] ) {
+ throw new Error(OpenAjax.hub.Error.Duplicate);
+ }
+ this._containers[containerId] = container;
+}
+
+/**
+ * Remove a container from this ManagedHub immediately
+ *
+ * This function can be called even if the ManagedHub is not in a CONNECTED state.
+ *
+ * @param {OpenAjax.hub.Container} container
+ * A Container to be removed from this ManagedHub
+ *
+ * @throws {OpenAjax.hub.Error.NoContainer} if no such container is found
+ */
+OpenAjax.hub.ManagedHub.prototype.removeContainer = function( container )
+{
+ var containerId = container.getClientID();
+ if ( ! this._containers[ containerId ] ) {
+ throw new Error(OpenAjax.hub.Error.NoContainer);
+ }
+ container.remove();
+ delete this._containers[ containerId ];
+}
+
+ /*** OpenAjax.hub.Hub interface implementation ***/
+
+/**
+ * Subscribe to a topic.
+ *
+ * This implementation of Hub.subscribe is synchronous. When subscribe
+ * is called:
+ *
+ * 1. The ManagedHub's onSubscribe callback is invoked. The
+ * container parameter is null, because the manager application,
+ * rather than a container, is subscribing.
+ * 2. If onSubscribe returns true, then the subscription is created.
+ * 3. The onComplete callback is invoked.
+ * 4. Then this function returns.
+ *
+ * @param {String} topic
+ * A valid topic string. MAY include wildcards.
+ * @param {Function} onData
+ * Callback function that is invoked whenever an event is
+ * published on the topic
+ * @param {Object} [scope]
+ * When onData callback or onComplete callback is invoked,
+ * the JavaScript "this" keyword refers to this scope object.
+ * If no scope is provided, default is window.
+ * @param {Function} [onComplete]
+ * Invoked to tell the client application whether the
+ * subscribe operation succeeded or failed.
+ * @param {*} [subscriberData]
+ * Client application provides this data, which is handed
+ * back to the client application in the subscriberData
+ * parameter of the onData and onComplete callback functions.
+ *
+ * @returns subscriptionID
+ * Identifier representing the subscription. This identifier is an
+ * arbitrary ID string that is unique within this Hub instance
+ * @type {String}
+ *
+ * @throws {OpenAjax.hub.Error.Disconnected} if this Hub instance is not in CONNECTED state
+ * @throws {OpenAjax.hub.Error.BadParameters} if the topic is invalid (e.g. contains an empty token)
+ */
+OpenAjax.hub.ManagedHub.prototype.subscribe = function( topic, onData, scope, onComplete, subscriberData )
+{
+ this._assertConn();
+ this._assertSubTopic(topic);
+ if ( ! onData ) {
+ throw new Error( OpenAjax.hub.Error.BadParameters );
+ }
+
+ scope = scope || window;
+
+ // check subscribe permission
+ if ( ! this._invokeOnSubscribe( topic, null ) ) {
+ this._invokeOnComplete( onComplete, scope, null, false, OpenAjax.hub.Error.NotAllowed );
+ return;
+ }
+
+ // on publish event, check publish permissions
+ var that = this;
+ function publishCB( topic, data, sd, pcont ) {
+ if ( that._invokeOnPublish( topic, data, pcont, null ) ) {
+ try {
+ onData.call( scope, topic, data, subscriberData );
+ } catch( e ) {
+ OpenAjax.hub._debugger();
+ that._log( "caught error from onData callback to Hub.subscribe(): " + e.message );
+ }
+ }
+ }
+ var subID = this._subscribe( topic, publishCB, scope, subscriberData );
+ this._invokeOnComplete( onComplete, scope, subID, true );
+ return subID;
+}
+
+/**
+ * Publish an event on a topic
+ *
+ * This implementation of Hub.publish is synchronous. When publish
+ * is called:
+ *
+ * 1. The target subscriptions are identified.
+ * 2. For each target subscription, the ManagedHub's onPublish
+ * callback is invoked. Data is only delivered to a target
+ * subscription if the onPublish callback returns true.
+ * The pcont parameter of the onPublish callback is null.
+ * This is because the ManagedHub, rather than a container,
+ * is publishing the data.
+ *
+ * @param {String} topic
+ * A valid topic string. MUST NOT include wildcards.
+ * @param {*} data
+ * Valid publishable data. To be portable across different
+ * Container implementations, this value SHOULD be serializable
+ * as JSON.
+ *
+ * @throws {OpenAjax.hub.Error.Disconnected} if this Hub instance is not in CONNECTED state
+ * @throws {OpenAjax.hub.Error.BadParameters} if the topic cannot be published (e.g. contains
+ * wildcards or empty tokens) or if the data cannot be published (e.g. cannot be serialized as JSON)
+ */
+OpenAjax.hub.ManagedHub.prototype.publish = function( topic, data )
+{
+ this._assertConn();
+ this._assertPubTopic(topic);
+ this._publish( topic, data, null );
+}
+
+/**
+ * Unsubscribe from a subscription
+ *
+ * This implementation of Hub.unsubscribe is synchronous. When unsubscribe
+ * is called:
+ *
+ * 1. The subscription is destroyed.
+ * 2. The ManagedHub's onUnsubscribe callback is invoked, if there is one.
+ * 3. The onComplete callback is invoked.
+ * 4. Then this function returns.
+ *
+ * @param {String} subscriptionID
+ * A subscriptionID returned by Hub.subscribe()
+ * @param {Function} [onComplete]
+ * Callback function invoked when unsubscribe completes
+ * @param {Object} [scope]
+ * When onComplete callback function is invoked, the JavaScript "this"
+ * keyword refers to this scope object.
+ * If no scope is provided, default is window.
+ *
+ * @throws {OpenAjax.hub.Error.Disconnected} if this Hub instance is not in CONNECTED state
+ * @throws {OpenAjax.hub.Error.NoSubscription} if no such subscription is found
+ */
+OpenAjax.hub.ManagedHub.prototype.unsubscribe = function( subscriptionID, onComplete, scope )
+{
+ this._assertConn();
+ if ( ! subscriptionID ) {
+ throw new Error( OpenAjax.hub.Error.BadParameters );
+ }
+ this._unsubscribe( subscriptionID );
+ this._invokeOnUnsubscribe( null, subscriptionID );
+ this._invokeOnComplete( onComplete, scope, subscriptionID, true );
+}
+
+/**
+ * Returns true if disconnect() has NOT been called on this ManagedHub,
+ * else returns false
+ *
+ * @returns Boolean
+ * @type {Boolean}
+ */
+OpenAjax.hub.ManagedHub.prototype.isConnected = function()
+{
+ return this._active;
+}
+
+/**
+* Returns the scope associated with this Hub instance and which will be used
+* with callback functions.
+*
+* This function can be called even if the Hub is not in a CONNECTED state.
+*
+* @returns scope object
+* @type {Object}
+ */
+OpenAjax.hub.ManagedHub.prototype.getScope = function()
+{
+ return this._scope;
+}
+
+/**
+ * Returns the subscriberData parameter that was provided when
+ * Hub.subscribe was called.
+ *
+ * @param subscriberID
+ * The subscriberID of a subscription
+ *
+ * @returns subscriberData
+ * @type {*}
+ *
+ * @throws {OpenAjax.hub.Error.Disconnected} if this Hub instance is not in CONNECTED state
+ * @throws {OpenAjax.hub.Error.NoSubscription} if there is no such subscription
+ */
+OpenAjax.hub.ManagedHub.prototype.getSubscriberData = function( subscriberID )
+{
+ this._assertConn();
+ var path = subscriberID.split(".");
+ var sid = path.pop();
+ var sub = this._getSubscriptionObject( this._subscriptions, path, 0, sid );
+ if ( sub )
+ return sub.data;
+ throw new Error( OpenAjax.hub.Error.NoSubscription );
+}
+
+/**
+ * Returns the scope associated with a specified subscription. This scope will
+ * be used when invoking the 'onData' callback supplied to Hub.subscribe().
+ *
+ * @param subscriberID
+ * The subscriberID of a subscription
+ *
+ * @returns scope
+ * @type {*}
+ *
+ * @throws {OpenAjax.hub.Error.Disconnected} if this Hub instance is not in CONNECTED state
+ * @throws {OpenAjax.hub.Error.NoSubscription} if there is no such subscription
+ */
+OpenAjax.hub.ManagedHub.prototype.getSubscriberScope = function( subscriberID )
+{
+ this._assertConn();
+ var path = subscriberID.split(".");
+ var sid = path.pop();
+ var sub = this._getSubscriptionObject( this._subscriptions, path, 0, sid );
+ if ( sub )
+ return sub.scope;
+ throw new Error( OpenAjax.hub.Error.NoSubscription );
+}
+
+/**
+ * Returns the params object associated with this Hub instance.
+ * Allows mix-in code to access parameters passed into constructor that created
+ * this Hub instance.
+ *
+ * @returns params the params object associated with this Hub instance
+ * @type {Object}
+ */
+OpenAjax.hub.ManagedHub.prototype.getParameters = function()
+{
+ return this._p;
+}
+
+
+/* PRIVATE FUNCTIONS */
+
+/**
+ * Send a message to a container's client.
+ * This is an OAH subscriber's data callback. It is private to ManagedHub
+ * and serves as an adapter between the OAH 1.0 API and Container.sendToClient.
+ *
+ * @param {String} topic Topic on which data was published
+ * @param {Object} data Data to be delivered to the client
+ * @param {Object} sd Object containing properties
+ * c: container to which data must be sent
+ * sid: subscription ID within that container
+ * @param {Object} pcont Publishing container, or null if this data was
+ * published by the manager
+ */
+OpenAjax.hub.ManagedHub.prototype._sendToClient = function(topic, data, sd, pcont)
+{
+ if (!this.isConnected()) {
+ return;
+ }
+ if ( this._invokeOnPublish( topic, data, pcont, sd.c ) ) {
+ sd.c.sendToClient( topic, data, sd.sid );
+ }
+}
+
+OpenAjax.hub.ManagedHub.prototype._assertConn = function()
+{
+ if (!this.isConnected()) {
+ throw new Error(OpenAjax.hub.Error.Disconnected);
+ }
+}
+
+OpenAjax.hub.ManagedHub.prototype._assertPubTopic = function(topic)
+{
+ if ( !topic || topic === "" || (topic.indexOf("*") != -1) ||
+ (topic.indexOf("..") != -1) || (topic.charAt(0) == ".") ||
+ (topic.charAt(topic.length-1) == "."))
+ {
+ throw new Error(OpenAjax.hub.Error.BadParameters);
+ }
+}
+
+OpenAjax.hub.ManagedHub.prototype._assertSubTopic = function(topic)
+{
+ if ( ! topic ) {
+ throw new Error(OpenAjax.hub.Error.BadParameters);
+ }
+ var path = topic.split(".");
+ var len = path.length;
+ for (var i = 0; i < len; i++) {
+ var p = path[i];
+ if ((p === "") ||
+ ((p.indexOf("*") != -1) && (p != "*") && (p != "**"))) {
+ throw new Error(OpenAjax.hub.Error.BadParameters);
+ }
+ if ((p == "**") && (i < len - 1)) {
+ throw new Error(OpenAjax.hub.Error.BadParameters);
+ }
+ }
+}
+
+OpenAjax.hub.ManagedHub.prototype._invokeOnComplete = function( func, scope, item, success, errorCode )
+{
+ if ( func ) { // onComplete is optional
+ try {
+ scope = scope || window;
+ func.call( scope, item, success, errorCode );
+ } catch( e ) {
+ OpenAjax.hub._debugger();
+ this._log( "caught error from onComplete callback: " + e.message );
+ }
+ }
+}
+
+OpenAjax.hub.ManagedHub.prototype._invokeOnPublish = function( topic, data, pcont, scont )
+{
+ try {
+ return this._p.onPublish.call( this._scope, topic, data, pcont, scont );
+ } catch( e ) {
+ OpenAjax.hub._debugger();
+ this._log( "caught error from onPublish callback to constructor: " + e.message );
+ }
+ return false;
+}
+
+OpenAjax.hub.ManagedHub.prototype._invokeOnSubscribe = function( topic, container )
+{
+ try {
+ return this._p.onSubscribe.call( this._scope, topic, container );
+ } catch( e ) {
+ OpenAjax.hub._debugger();
+ this._log( "caught error from onSubscribe callback to constructor: " + e.message );
+ }
+ return false;
+}
+
+OpenAjax.hub.ManagedHub.prototype._invokeOnUnsubscribe = function( container, managerSubID )
+{
+ if ( this._onUnsubscribe ) {
+ var topic = managerSubID.slice( 0, managerSubID.lastIndexOf(".") );
+ try {
+ this._onUnsubscribe.call( this._scope, topic, container );
+ } catch( e ) {
+ OpenAjax.hub._debugger();
+ this._log( "caught error from onUnsubscribe callback to constructor: " + e.message );
+ }
+ }
+}
+
+OpenAjax.hub.ManagedHub.prototype._subscribe = function( topic, onData, scope, subscriberData )
+{
+ var handle = topic + "." + this._seq;
+ var sub = { scope: scope, cb: onData, data: subscriberData, sid: this._seq++ };
+ var path = topic.split(".");
+ this._recursiveSubscribe( this._subscriptions, path, 0, sub );
+ return handle;
+}
+
+OpenAjax.hub.ManagedHub.prototype._recursiveSubscribe = function(tree, path, index, sub)
+{
+ var token = path[index];
+ if (index == path.length) {
+ sub.next = tree.s;
+ tree.s = sub;
+ } else {
+ if (typeof tree.c == "undefined") {
+ tree.c = {};
+ }
+ if (typeof tree.c[token] == "undefined") {
+ tree.c[token] = { c: {}, s: null };
+ this._recursiveSubscribe(tree.c[token], path, index + 1, sub);
+ } else {
+ this._recursiveSubscribe( tree.c[token], path, index + 1, sub);
+ }
+ }
+}
+
+OpenAjax.hub.ManagedHub.prototype._publish = function( topic, data, pcont )
+{
+ // if we are currently handling a publish event, then queue this request
+ // and handle later, one by one
+ if ( this._isPublishing ) {
+ this._pubQ.push( { t: topic, d: data, p: pcont } );
+ return;
+ }
+
+ this._safePublish( topic, data, pcont );
+
+ while ( this._pubQ.length > 0 ) {
+ var pub = this._pubQ.shift();
+ this._safePublish( pub.t, pub.d, pub.p );
+ }
+}
+
+OpenAjax.hub.ManagedHub.prototype._safePublish = function( topic, data, pcont )
+{
+ this._isPublishing = true;
+ var path = topic.split(".");
+ this._recursivePublish( this._subscriptions, path, 0, topic, data, pcont );
+ this._isPublishing = false;
+}
+
+OpenAjax.hub.ManagedHub.prototype._recursivePublish = function(tree, path, index, name, msg, pcont)
+{
+ if (typeof tree != "undefined") {
+ var node;
+ if (index == path.length) {
+ node = tree;
+ } else {
+ this._recursivePublish(tree.c[path[index]], path, index + 1, name, msg, pcont);
+ this._recursivePublish(tree.c["*"], path, index + 1, name, msg, pcont);
+ node = tree.c["**"];
+ }
+ if (typeof node != "undefined") {
+ var sub = node.s;
+ while ( sub ) {
+ var sc = sub.scope;
+ var cb = sub.cb;
+ var d = sub.data;
+ if (typeof cb == "string") {
+ // get a function object
+ cb = sc[cb];
+ }
+ cb.call(sc, name, msg, d, pcont);
+ sub = sub.next;
+ }
+ }
+ }
+}
+
+OpenAjax.hub.ManagedHub.prototype._unsubscribe = function( subscriptionID )
+{
+ var path = subscriptionID.split(".");
+ var sid = path.pop();
+ if ( ! this._recursiveUnsubscribe( this._subscriptions, path, 0, sid ) ) {
+ throw new Error( OpenAjax.hub.Error.NoSubscription );
+ }
+}
+
+/**
+ * @returns 'true' if properly unsubscribed; 'false' otherwise
+ */
+OpenAjax.hub.ManagedHub.prototype._recursiveUnsubscribe = function(tree, path, index, sid)
+{
+ if ( typeof tree == "undefined" ) {
+ return false;
+ }
+
+ if (index < path.length) {
+ var childNode = tree.c[path[index]];
+ if ( ! childNode ) {
+ return false;
+ }
+ this._recursiveUnsubscribe(childNode, path, index + 1, sid);
+ if ( ! childNode.s ) {
+ for (var x in childNode.c) {
+ return true;
+ }
+ delete tree.c[path[index]];
+ }
+ } else {
+ var sub = tree.s;
+ var sub_prev = null;
+ var found = false;
+ while ( sub ) {
+ if ( sid == sub.sid ) {
+ found = true;
+ if ( sub == tree.s ) {
+ tree.s = sub.next;
+ } else {
+ sub_prev.next = sub.next;
+ }
+ break;
+ }
+ sub_prev = sub;
+ sub = sub.next;
+ }
+ if ( ! found ) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+OpenAjax.hub.ManagedHub.prototype._getSubscriptionObject = function( tree, path, index, sid )
+{
+ if (typeof tree != "undefined") {
+ if (index < path.length) {
+ var childNode = tree.c[path[index]];
+ return this._getSubscriptionObject(childNode, path, index + 1, sid);
+ }
+
+ var sub = tree.s;
+ while ( sub ) {
+ if ( sid == sub.sid ) {
+ return sub;
+ }
+ sub = sub.next;
+ }
+ }
+ return null;
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Container
+ * @constructor
+ *
+ * Container represents an instance of a manager-side object that contains and
+ * communicates with a single client of the hub. The container might be an inline
+ * container, an iframe FIM container, or an iframe PostMessage container, or
+ * it might be an instance of some other implementation.
+ *
+ * @param {OpenAjax.hub.ManagedHub} hub
+ * Managed Hub instance
+ * @param {String} clientID
+ * A string ID that identifies a particular client of a Managed Hub. Unique
+ * within the context of the ManagedHub.
+ * @param {Object} params
+ * Parameters used to instantiate the Container.
+ * Once the constructor is called, the params object belongs exclusively to
+ * the Container. The caller MUST not modify it.
+ * Implementations of Container may specify additional properties
+ * for the params object, besides those identified below.
+ * The following params properties MUST be supported by all Container
+ * implementations:
+ * @param {Function} params.Container.onSecurityAlert
+ * Called when an attempted security breach is thwarted. Function is defined
+ * as follows: function(container, securityAlert)
+ * @param {Function} [params.Container.onConnect]
+ * Called when the client connects to the Managed Hub. Function is defined
+ * as follows: function(container)
+ * @param {Function} [params.Container.onDisconnect]
+ * Called when the client disconnects from the Managed Hub. Function is
+ * defined as follows: function(container)
+ * @param {Object} [params.Container.scope]
+ * Whenever one of the Container's callback functions is called, references
+ * to "this" in the callback will refer to the scope object. If no scope is
+ * provided, default is window.
+ * @param {Function} [params.Container.log]
+ * Optional logger function. Would be used to log to console.log or
+ * equivalent.
+ *
+ * @throws {OpenAjax.hub.Error.BadParameters} if required params are not
+ * present or null
+ * @throws {OpenAjax.hub.Error.Duplicate} if a Container with this clientID
+ * already exists in the given Managed Hub
+ * @throws {OpenAjax.hub.Error.Disconnected} if ManagedHub is not connected
+ */
+//OpenAjax.hub.Container = function( hub, clientID, params ) {}
+
+/**
+ * Send a message to the client inside this container. This function MUST only
+ * be called by ManagedHub.
+ *
+ * @param {String} topic
+ * The topic name for the published message
+ * @param {*} data
+ * The payload. Can be any JSON-serializable value.
+ * @param {String} containerSubscriptionId
+ * Container's ID for a subscription, from previous call to
+ * subscribeForClient()
+ */
+//OpenAjax.hub.Container.prototype.sendToClient = function( topic, data, containerSubscriptionId ) {}
+
+/**
+ * Shut down a container. remove does all of the following:
+ * - disconnects container from HubClient
+ * - unsubscribes from all of its existing subscriptions in the ManagedHub
+ *
+ * This function is only called by ManagedHub.removeContainer
+ * Calling this function does NOT cause the container's onDisconnect callback to
+ * be invoked.
+ */
+//OpenAjax.hub.Container.prototype.remove = function() {}
+
+/**
+ * Returns true if the given client is connected to the managed hub.
+ * Else returns false.
+ *
+ * @returns true if the client is connected to the managed hub
+ * @type boolean
+ */
+//OpenAjax.hub.Container.prototype.isConnected = function() {}
+
+/**
+ * Returns the clientID passed in when this Container was instantiated.
+ *
+ * @returns The clientID
+ * @type {String}
+ */
+//OpenAjax.hub.Container.prototype.getClientID = function() {}
+
+/**
+ * If DISCONNECTED:
+ * Returns null
+ * If CONNECTED:
+ * Returns the origin associated with the window containing the HubClient
+ * associated with this Container instance. The origin has the format
+ *
+ * [protocol]://[host]
+ *
+ * where:
+ *
+ * [protocol] is "http" or "https"
+ * [host] is the hostname of the partner page.
+ *
+ * @returns Partner's origin
+ * @type {String}
+ */
+//OpenAjax.hub.Container.prototype.getPartnerOrigin = function() {}
+
+/**
+ * Returns the params object associated with this Container instance.
+ *
+ * @returns params
+ * The params object associated with this Container instance
+ * @type {Object}
+ */
+//OpenAjax.hub.Container.prototype.getParameters = function() {}
+
+/**
+ * Returns the ManagedHub to which this Container belongs.
+ *
+ * @returns ManagedHub
+ * The ManagedHub object associated with this Container instance
+ * @type {OpenAjax.hub.ManagedHub}
+ */
+//OpenAjax.hub.Container.prototype.getHub = function() {}
+
+////////////////////////////////////////////////////////////////////////////////
+
+/*
+ * Unmanaged Hub
+ */
+
+/**
+ * OpenAjax.hub._hub is the default ManagedHub instance that we use to
+ * provide OAH 1.0 behavior.
+ */
+OpenAjax.hub._hub = new OpenAjax.hub.ManagedHub({
+ onSubscribe: function(topic, ctnr) { return true; },
+ onPublish: function(topic, data, pcont, scont) { return true; }
+});
+
+/**
+ * Subscribe to a topic.
+ *
+ * @param {String} topic
+ * A valid topic string. MAY include wildcards.
+ * @param {Function|String} onData
+ * Callback function that is invoked whenever an event is published on the
+ * topic. If 'onData' is a string, then it represents the name of a
+ * function on the 'scope' object.
+ * @param {Object} [scope]
+ * When onData callback is invoked,
+ * the JavaScript "this" keyword refers to this scope object.
+ * If no scope is provided, default is window.
+ * @param {*} [subscriberData]
+ * Client application provides this data, which is handed
+ * back to the client application in the subscriberData
+ * parameter of the onData callback function.
+ *
+ * @returns {String} Identifier representing the subscription.
+ *
+ * @throws {OpenAjax.hub.Error.BadParameters} if the topic is invalid
+ * (e.g.contains an empty token)
+ */
+OpenAjax.hub.subscribe = function(topic, onData, scope, subscriberData)
+{
+ // resolve the 'onData' function if it is a string
+ if ( typeof onData === "string" ) {
+ scope = scope || window;
+ onData = scope[ onData ] || null;
+ }
+
+ return OpenAjax.hub._hub.subscribe( topic, onData, scope, null, subscriberData );
+}
+
+/**
+ * Unsubscribe from a subscription.
+ *
+ * @param {String} subscriptionID
+ * Subscription identifier returned by subscribe()
+ *
+ * @throws {OpenAjax.hub.Error.NoSubscription} if no such subscription is found
+ */
+OpenAjax.hub.unsubscribe = function(subscriptionID)
+{
+ return OpenAjax.hub._hub.unsubscribe( subscriptionID );
+}
+
+/**
+ * Publish an event on a topic.
+ *
+ * @param {String} topic
+ * A valid topic string. MUST NOT include wildcards.
+ * @param {*} data
+ * Valid publishable data.
+ *
+ * @throws {OpenAjax.hub.Error.BadParameters} if the topic cannot be published
+ * (e.g. contains wildcards or empty tokens)
+ */
+OpenAjax.hub.publish = function(topic, data)
+{
+ OpenAjax.hub._hub.publish(topic, data);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+// Register the OpenAjax Hub itself as a library.
+OpenAjax.hub.registerLibrary("OpenAjax", "http://openajax.org/hub", "2.0", {});
+
+} // !OpenAjax.hub
Copied: shindig/branches/2.0.x/extras/src/main/javascript/features-extras/org.openajax.hub-2.0.5/crypto.js (from r998422, shindig/branches/2.0.x/extras/src/main/javascript/features-extras/org.openajax.hub-2.0.4/crypto.js)
URL: http://svn.apache.org/viewvc/shindig/branches/2.0.x/extras/src/main/javascript/features-extras/org.openajax.hub-2.0.5/crypto.js?p2=shindig/branches/2.0.x/extras/src/main/javascript/features-extras/org.openajax.hub-2.0.5/crypto.js&p1=shindig/branches/2.0.x/extras/src/main/javascript/features-extras/org.openajax.hub-2.0.4/crypto.js&r1=998422&r2=1005506&rev=1005506&view=diff
==============================================================================
(empty)
Added: shindig/branches/2.0.x/extras/src/main/javascript/features-extras/org.openajax.hub-2.0.5/feature.xml
URL: http://svn.apache.org/viewvc/shindig/branches/2.0.x/extras/src/main/javascript/features-extras/org.openajax.hub-2.0.5/feature.xml?rev=1005506&view=auto
==============================================================================
--- shindig/branches/2.0.x/extras/src/main/javascript/features-extras/org.openajax.hub-2.0.5/feature.xml (added)
+++ shindig/branches/2.0.x/extras/src/main/javascript/features-extras/org.openajax.hub-2.0.5/feature.xml Thu Oct 7 15:54:09 2010
@@ -0,0 +1,32 @@
+<?xml version="1.0"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations under the License.
+-->
+<feature>
+ <name>org.openajax.hub-2.0.5</name>
+ <dependency>rpc</dependency>
+ <gadget>
+ <script src="OpenAjax-mashup.js"/>
+ <script src="iframe.js"/>
+ <script src="crypto.js"/>
+ </gadget>
+ <container>
+ <script src="OpenAjax-mashup.js"/>
+ <script src="iframe.js"/>
+ <script src="crypto.js"/>
+ </container>
+</feature>