/*
* 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.
*/
/**
* Contains the space where the gadget renders.
*
* @module explorer/widgets/gadgetarea/GadgetArea
* @augments dijit/_WidgetBase
* @augments dijit/_TemplatedMixin
* @see {@link http://dojotoolkit.org/reference-guide/1.8/dijit/_WidgetBase.html|WidgetBase Documentation}
* @see {@link http://dojotoolkit.org/reference-guide/1.8/dijit/_TemplatedMixin.html|TemplatedMixin Documentation}
*/
define(['dojo/_base/declare', 'dijit/_WidgetBase', 'dijit/_TemplatedMixin', 'dojo/topic',
'dojo/_base/array', 'dojo/text!./../../templates/GadgetArea.html', './GadgetToolbar',
'dojo/dom-construct','../Loading', '../../opensocial-data', './GadgetModalDialog',
'dojo/_base/window', 'dojo/dom', 'dojo/json', '../../ExplorerContainer', 'dojo/on', 'dojo/Deferred',
'./LocationMenuItem'],
function(declare, WidgetBase, TemplatedMixin, topic, arrayUtil, template, GadgetToolbar,
domConstruct, Loading, osData, GadgetModalDialog, win, dom, JSON, ExplorerContainer, on, Deferred,
LocationMenuItem) {
return declare('GadgetAreaWidget', [ WidgetBase, TemplatedMixin ], {
templateString : template,
containerToken : null,
containerTokenTTL : 3600,
/**
* Called right after this widget has been added to the DOM.
*
* @memberof module:explorer/widgets/gadgetarea/GadgetArea#
* @see {@link http://dojotoolkit.org/reference-guide/1.8/dijit/_WidgetBase.html|Dojo Documentation}
*/
startup : function() {
this.expContainer = new ExplorerContainer();
this.siteCounter = 0;
this.siteParent = this.domNode;
this.gadgetToolbar = new GadgetToolbar();
domConstruct.place(this.gadgetToolbar.domNode, this.domNode);
this.gadgetToolbar.startup();
this.addMenuItems();
var self = this;
this.loadingWidget = new Loading();
domConstruct.place(this.loadingWidget.domNode, this.domNode);
this.loadingWidget.startup();
this.setupEventListeners();
this.setupSubscriptions();
},
/**
* Setups topic subscriptions for this class.
*
* @memberof module:explorer/widgets/gadgetarea/GadgetArea#
*/
setupSubscriptions : function() {
var self = this;
//Published when a gadget switches views via the menu
this.reRenderGadgetViewHandle = topic.subscribe('reRenderGadgetView', function(params) {
self.reRenderGadget(params);
});
// When a user logs in and a security token is generated, we update it in this module.
this.updateTokenHandle = topic.subscribe("updateToken", function(token, ttl) {
self.updateContainerSecurityToken(token, ttl);
});
},
/**
* Sets up event listeners for this class. Override this method to add additional event listeners.
*
* @memberof module:explorer/widgets/gadgetarea/GadgetArea#
*/
setupEventListeners : function() {
var self = this;
on(this.getExplorerContainer(), 'gadgetrendered', function(gadgetUrl, siteId) {
self.loadingWidget.hide();
});
on(this.getExplorerContainer(), 'addaction', function(action) {
self.gadgetToolbar.addAction(action);
});
on(this.getExplorerContainer(), 'removeaction', function(action) {
self.gadgetToolbar.removeAction(action);
});
on(this.getExplorerContainer(), 'navigateurl', function(rel, opt_viewTarget, opt_coordinates, parentSite, opt_callback) {
opt_callback(self.createDialog('URL', opt_viewTarget));
});
on(this.getExplorerContainer(), 'navigategadget', function(metadata, rel, opt_view, opt_viewTarget, opt_coordinates, parentSite, opt_callback) {
var title = 'Gadget';
if(metadata.modulePrefs && metadata.modulePrefs.title) {
title = metadata.modulePrefs.title;
}
opt_callback(self.createDialog(title, opt_viewTarget));
});
on(this.getExplorerContainer(), 'navigateee', function(el, opt_gadgetInfo, opt_viewTarget, opt_coordinates, parentSite, opt_callback) {
var title = 'Embedded Experiences';
if(opt_gadgetInfo && opt_gadgetInfo.modulePrefs && opt_gadgetInfo.modulePrefs.title) {
title = opt_gadgetInfo.modulePrefs.title;
}
opt_callback(self.createDialog(title, opt_viewTarget));
});
on(this.getExplorerContainer(), 'destroyelement', function(site) {
self.gadgetDialog.hide(site);
});
on(this.getExplorerContainer(), 'navigateforactions', function(gadgetUrl, opt_params) {
// We can effectively ignore gadgetUrl, because we'll get it from the site's holder in reRenderGadget
self.reRenderGadget(opt_params);
});
},
/**
* Gets the {@link module:explorer/widgets/ExplorerContainer}.
* @memberof module:explorer/widgets/gadgetarea/GadgetArea#
*/
getExplorerContainer : function() {
return this.expContainer;
},
/**
* Renders the gadget given its URL.
*
* @memberof module:explorer/widgets/gadgetarea/GadgetArea#
* @param {String} url - The URL where the gadget is located.
* @param {Object=} opt_renderParams - Optional parameter used by the container, see the
* {@link http://opensocial.github.io/spec/2.5/Core-Container.xml#RenderConfiguration|OpenSocial spec}
* for more details about how this object should be constructed.
* @returns {module:dojo/promise/Promise} Returns a
* {@link http://dojotoolkit.org/reference-guide/1.8/dojo/promise/Promise.html#dojo-promise-promise|Dojo Promise}.
* Call the then method of this Promise with a function that takes in one parameter, the gadget metadata.
*/
renderGadget : function(url, opt_renderParams) {
this.closeOpenSite();
this.loadingWidget.show();
this.site = this.createSite();
var self = this;
var deferred = new Deferred();
this.getExplorerContainer().renderGadget(url, this.site, opt_renderParams).then(function(metadata) {
if(metadata && metadata[url]) {
self.gadgetToolbar.setGadgetMetadata(metadata[url]);
}
deferred.resolve(metadata);
});
return deferred;
},
/**
* Renders an embedded experience.
*
* @memberof module:explorer/widgets/gadgetarea/GadgetArea#
* @param {String} url - The URL where the embedded experience is located.
* @param {String} dataModel - A stringified JSON object containing just the context property
* from the {@link http://opensocial.github.io/spec/2.5/Core-Gadget.xml#Embedded-Experiences|embedded experiences data model}.
* The gadget property of the embedded experiences data model will be the URL parameter.
* @returns {module:dojo/promise/Promise} Returns a
* {@link http://dojotoolkit.org/reference-guide/1.8/dojo/promise/Promise.html#dojo-promise-promise|Dojo Promise}.
* Call the then method of this Promise with a function that takes in one parameter, the gadget metadata and the
* {@link http://opensocial.github.io/spec/2.5/Core-Container.xml#osapi.container.GadgetSite|osapi.container.GadgetSite|gadget site}.
*/
renderEmbeddedExperience : function(url, dataModel) {
var oDataModel = JSON.parse(dataModel);
oDataModel.gadget = url;
this.closeOpenSite();
this.loadingWidget.show();
var self = this;
var deferred = new Deferred();
this.getExplorerContainer().renderEmbeddedExperience(oDataModel, this.createNodeForSite()).then(function(results) {
self.site = results.site;
if(results.metadata && results.metadata[oDataModel.gadget]) {
self.gadgetToolbar.setGadgetMetadata(results.metadata[oDataModel.gadget]);
}
deferred.resolve(results);
});
return deferred;
},
/**
* Rerenders the currently rendered gadget.
*
* @memberof module:explorer/widgets/gadgetarea/GadgetArea#
* @param {Object=} opt_renderParams - Optional render params. See
* {@link http://opensocial.github.io/spec/2.5/Core-Container.xml#RenderConfiguration|OpenSocial spec}
* for more details about how this object should be constructed.
*/
reRenderGadget : function(opt_renderParams) {
this.renderGadget(this.site.getActiveSiteHolder().getUrl(), opt_renderParams);
},
/**
* Creates a modal dialog. Typically used when handling open-views requests from the gadget.
*
* @memberof module:explorer/widgets/gadgetarea/GadgetArea#
* @param {String} title - The title to give the dialog.
* @param {String} viewTarget - Should be one of the
* {@link http://opensocial.github.io/spec/2.5/Core-Gadget.xml#gadgets.views.ViewType.ViewTarget|view targets}
* defined in the OpenSocial spec.
*/
createDialog : function(title, viewTarget) {
if(this.gadgetDialog) {
this.gadgetDialog.destroy();
}
this.gadgetDialog = new GadgetModalDialog({"title" : title, "viewTarget" : viewTarget,
"container" : this.getExplorerContainer().getContainer()});
domConstruct.place(this.gadgetDialog.domNode, win.body());
this.gadgetDialog.startup();
this.gadgetDialog.show();
return this.gadgetDialog.getGadgetNode();
},
/**
* Destroys this widget.
*
* @memberof module:explorer/widgets/gadgetarea/GadgetArea#
* @see {@link http://dojotoolkit.org/reference-guide/1.8/dijit/_WidgetBase.html|Dojo Documentation}
*/
destroy : function() {
this.inherited(arguments);
if(this.gadgetDialog) {
this.gadgetDialog.destroy();
}
if(this.reRenderGadgetViewHandle) {
this.reRenderGadgetViewHandle.remove();
}
if(this.updateTokenHandle) {
this.updateTokenHandle.remove();
}
},
/**
* Updates the container security token and forces a refresh of all of the gadget
* security tokens to ensure owner/viewer information is up-to-date.
*
* @memberof module:explorer/widgets/gadgetarea/GadgetArea#
* @param {String} token - The security token.
* @param {Number} ttl - The time to live for the security token.
*/
updateContainerSecurityToken : function(token, ttl) {
this.getExplorerContainer().updateContainerSecurityToken(token, ttl);
},
/**
* Creates an gadget site.
*
* @memberof module:explorer/widgets/gadgetarea/GadgetArea#
* @return Returns a new gadget site.
* @see {@link http://opensocial.github.io/spec/2.5/Core-Container.xml#osapi.container.GadgetSite|osapi.container.GadgetSite|OpenSocial Spec}
*/
createSite : function() {
var siteNode = this.createNodeForSite();
return this.getExplorerContainer().getContainer().newGadgetSite(siteNode);
},
/**
* Creates a DOM node to use for the gadget site.
*
* @memberof module:explorer/widgets/gadgetarea/GadgetArea#
* @returns {Element} A DOM node.
*/
createNodeForSite: function() {
// Let's be nice and reuse the same div for the site.
var siteNode = dom.byId("gadgetSite" + this.siteCounter.toString());
if (!siteNode) {
this.siteCounter += 1;
siteNode = domConstruct.create("div", {"id" : "gadgetSite" + this.siteCounter.toString()});
domConstruct.place(siteNode, this.siteParent);
}
return siteNode;
},
/**
* Closes the currently open gadget site.
*
* @memberof module:explorer/widgets/gadgetarea/GadgetArea#
*/
closeOpenSite: function() {
if(this.site) {
// IMPORTANT: The gadget must be unloaded before it is closed.
// Otherwise, getUrl() is undefined and no lifecycle events are fired
// for unload!!!
if(this.site && this.site.getActiveSiteHolder() && this.site.getActiveSiteHolder().getUrl()) {
this.getExplorerContainer().getContainer().unloadGadget(this.site.getActiveSiteHolder().getUrl());
}
this.getExplorerContainer().getContainer().closeGadget(this.site);
domConstruct.destroy("gadgetSite" + this.siteCounter.toString());
}
},
/**
* Adds menu items to the gadget menu. Sub-classes can override this method to
* add additional menus.
*
* @memberof module:explorer/widgets/gadgetarea/GadgetArea#
*/
addMenuItems: function() {
var locationMenuItem = new LocationMenuItem();
this.gadgetToolbar.addMenuItem(locationMenuItem);
locationMenuItem.startup();
}
});
});